Skip to content

Commit

Permalink
Tor V3 Patch
Browse files Browse the repository at this point in the history
  • Loading branch information
canewsin committed Nov 27, 2021
1 parent 454c0b2 commit eab7fc2
Show file tree
Hide file tree
Showing 4 changed files with 371 additions and 2 deletions.
1 change: 1 addition & 0 deletions plugins/AnnounceZero/AnnounceZeroPlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from Plugin import PluginManager
from util import helper
from Crypt import CryptEd25519
from Crypt import CryptRsa

allow_reload = False # No source reload supported in this plugin
Expand Down
340 changes: 340 additions & 0 deletions src/Crypt/CryptEd25519.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,340 @@
## ZeroNet onion V3 support
## The following copied code is copied from stem.util.ed25519 official Tor Project python3 lib
## url : https://gitweb.torproject.org/stem.git/tree/stem/util/ed25519.py
## the ##modified tag means that the function has been modified respect to the one used by stem lib
## the ##custom tag means that the function has been added by me and it's not present on the stem ed25519.py file
## every comment i make begins with ##
##
# The following is copied from...
#
# https://github.com/pyca/ed25519
#
# This is under the CC0 license. For more information please see...
#
# https://github.com/pyca/cryptography/issues/5068

# ed25519.py - Optimized version of the reference implementation of Ed25519
#
# Written in 2011? by Daniel J. Bernstein <[email protected]>
# 2013 by Donald Stufft <[email protected]>
# 2013 by Alex Gaynor <[email protected]>
# 2013 by Greg Price <[email protected]>
#
# To the extent possible under law, the author(s) have dedicated all copyright
# and related and neighboring rights to this software to the public domain
# worldwide. This software is distributed without any warranty.
#
# You should have received a copy of the CC0 Public Domain Dedication along
# with this software. If not, see
# <http://creativecommons.org/publicdomain/zero/1.0/>.

"""
NB: This code is not safe for use with secret keys or secret data.
The only safe use of this code is for verifying signatures on public messages.
Functions for computing the public key of a secret key and for signing
a message are included, namely publickey_unsafe and signature_unsafe,
for testing purposes only.
The root of the problem is that Python's long-integer arithmetic is
not designed for use in cryptography. Specifically, it may take more
or less time to execute an operation depending on the values of the
inputs, and its memory access patterns may also depend on the inputs.
This opens it to timing and cache side-channel attacks which can
disclose data to an attacker. We rely on Python's long-integer
arithmetic, so we cannot handle secrets without risking their disclosure.
"""

import hashlib
import operator
import sys
import base64


__version__ = "1.0.dev0"


# Useful for very coarse version differentiation.
PY3 = sys.version_info[0] == 3

if PY3:
indexbytes = operator.getitem
intlist2bytes = bytes
int2byte = operator.methodcaller("to_bytes", 1, "big")
else:
int2byte = chr
range = xrange

def indexbytes(buf, i):
return ord(buf[i])

def intlist2bytes(l):
return b"".join(chr(c) for c in l)


b = 256
q = 2 ** 255 - 19
l = 2 ** 252 + 27742317777372353535851937790883648493


def H(m):
return hashlib.sha512(m).digest()


def pow2(x, p):
"""== pow(x, 2**p, q)"""
while p > 0:
x = x * x % q
p -= 1
return x


def inv(z):
"""$= z^{-1} \mod q$, for z != 0"""
# Adapted from curve25519_athlon.c in djb's Curve25519.
z2 = z * z % q # 2
z9 = pow2(z2, 2) * z % q # 9
z11 = z9 * z2 % q # 11
z2_5_0 = (z11 * z11) % q * z9 % q # 31 == 2^5 - 2^0
z2_10_0 = pow2(z2_5_0, 5) * z2_5_0 % q # 2^10 - 2^0
z2_20_0 = pow2(z2_10_0, 10) * z2_10_0 % q # ...
z2_40_0 = pow2(z2_20_0, 20) * z2_20_0 % q
z2_50_0 = pow2(z2_40_0, 10) * z2_10_0 % q
z2_100_0 = pow2(z2_50_0, 50) * z2_50_0 % q
z2_200_0 = pow2(z2_100_0, 100) * z2_100_0 % q
z2_250_0 = pow2(z2_200_0, 50) * z2_50_0 % q # 2^250 - 2^0
return pow2(z2_250_0, 5) * z11 % q # 2^255 - 2^5 + 11 = q - 2


d = -121665 * inv(121666) % q
I = pow(2, (q - 1) // 4, q)


def xrecover(y):
xx = (y * y - 1) * inv(d * y * y + 1)
x = pow(xx, (q + 3) // 8, q)

if (x * x - xx) % q != 0:
x = (x * I) % q

if x % 2 != 0:
x = q-x

return x


By = 4 * inv(5)
Bx = xrecover(By)
B = (Bx % q, By % q, 1, (Bx * By) % q)
ident = (0, 1, 1, 0)


def edwards_add(P, Q):
# This is formula sequence 'addition-add-2008-hwcd-3' from
# http://www.hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html
(x1, y1, z1, t1) = P
(x2, y2, z2, t2) = Q

a = (y1-x1)*(y2-x2) % q
b = (y1+x1)*(y2+x2) % q
c = t1*2*d*t2 % q
dd = z1*2*z2 % q
e = b - a
f = dd - c
g = dd + c
h = b + a
x3 = e*f
y3 = g*h
t3 = e*h
z3 = f*g

return (x3 % q, y3 % q, z3 % q, t3 % q)


def edwards_double(P):
# This is formula sequence 'dbl-2008-hwcd' from
# http://www.hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html
(x1, y1, z1, t1) = P

a = x1*x1 % q
b = y1*y1 % q
c = 2*z1*z1 % q
# dd = -a
e = ((x1+y1)*(x1+y1) - a - b) % q
g = -a + b # dd + b
f = g - c
h = -a - b # dd - b
x3 = e*f
y3 = g*h
t3 = e*h
z3 = f*g

return (x3 % q, y3 % q, z3 % q, t3 % q)


def scalarmult(P, e):
if e == 0:
return ident
Q = scalarmult(P, e // 2)
Q = edwards_double(Q)
if e & 1:
Q = edwards_add(Q, P)
return Q


# Bpow[i] == scalarmult(B, 2**i)
Bpow = []


def make_Bpow():
P = B
for i in range(253):
Bpow.append(P)
P = edwards_double(P)
make_Bpow()


def scalarmult_B(e):
"""
Implements scalarmult(B, e) more efficiently.
"""
# scalarmult(B, l) is the identity
e = e % l
P = ident
for i in range(253):
if e & 1:
P = edwards_add(P, Bpow[i])
e = e // 2
assert e == 0, e
return P


def encodeint(y):
bits = [(y >> i) & 1 for i in range(b)]
return b''.join([
int2byte(sum([bits[i * 8 + j] << j for j in range(8)]))
for i in range(b//8)
])


def encodepoint(P):
(x, y, z, t) = P
zi = inv(z)
x = (x * zi) % q
y = (y * zi) % q
bits = [(y >> i) & 1 for i in range(b - 1)] + [x & 1]
return b''.join([
int2byte(sum([bits[i * 8 + j] << j for j in range(8)]))
for i in range(b // 8)
])


def bit(h, i):
return (indexbytes(h, i // 8) >> (i % 8)) & 1

##modified
def publickey_unsafe(sk):
"""
Not safe to use with secret keys or secret data.
See module docstring. This function should be used for testing only.
"""
##h = H(sk)
h = sk
a = 2 ** (b - 2) + sum(2 ** i * bit(h, i) for i in range(3, b - 2))
A = scalarmult_B(a)
return encodepoint(A)

##custom
## from stem.util.str_tools._to_unicode_impl
## from https://gitweb.torproject.org/stem.git/tree/stem/util/str_tools.py#n80
def to_unicode_impl(msg):
if msg is not None and not isinstance(msg, str):
return msg.decode('utf-8', 'replace')
else:
return msg

##custom
## rewritten stem.descriptor.hidden_service.address_from_identity_key
## from https://gitweb.torproject.org/stem.git/tree/stem/descriptor/hidden_service.py#n1088
def publickey_to_onionaddress(key):
CHECKSUM_CONSTANT = b'.onion checksum'
## version = stem.client.datatype.Size.CHAR.pack(3)
version = b'\x03'
checksum = hashlib.sha3_256(CHECKSUM_CONSTANT + key + version).digest()[:2]
onion_address = base64.b32encode(key + checksum + version)
return to_unicode_impl(onion_address + b'.onion').lower()


def Hint(m):
h = H(m)
return sum(2 ** i * bit(h, i) for i in range(2 * b))

##modified
def signature_unsafe(m, sk, pk):
"""
Not safe to use with secret keys or secret data.
See module docstring. This function should be used for testing only.
"""
##h = H(sk)
h = sk
a = 2 ** (b - 2) + sum(2 ** i * bit(h, i) for i in range(3, b - 2))
r = Hint(
intlist2bytes([indexbytes(h, j) for j in range(b // 8, b // 4)]) + m
)
R = scalarmult_B(r)
S = (r + Hint(encodepoint(R) + pk + m) * a) % l
return encodepoint(R) + encodeint(S)


def isoncurve(P):
(x, y, z, t) = P
return (z % q != 0 and
x*y % q == z*t % q and
(y*y - x*x - z*z - d*t*t) % q == 0)


def decodeint(s):
return sum(2 ** i * bit(s, i) for i in range(0, b))


def decodepoint(s):
y = sum(2 ** i * bit(s, i) for i in range(0, b - 1))
x = xrecover(y)
if x & 1 != bit(s, b-1):
x = q - x
P = (x, y, 1, (x*y) % q)
if not isoncurve(P):
raise ValueError("decoding point that is not on curve")
return P


class SignatureMismatch(Exception):
pass


def checkvalid(s, m, pk):
"""
Not safe to use when any argument is secret.
See module docstring. This function should be used only for
verifying public signatures of public messages.
"""
if len(s) != b // 4:
raise ValueError("signature length is wrong")

if len(pk) != b // 8:
raise ValueError("public-key length is wrong")

R = decodepoint(s[:b // 8])
A = decodepoint(pk)
S = decodeint(s[b // 8:b // 4])
h = Hint(encodepoint(R) + pk + m)

(x1, y1, z1, t1) = P = scalarmult_B(S)
(x2, y2, z2, t2) = Q = edwards_add(R, scalarmult(A, h))

if (not isoncurve(P) or not isoncurve(Q) or
(x1*z2 - x2*z1) % q != 0 or (y1*z2 - y2*z1) % q != 0):
raise SignatureMismatch("signature does not pass verification")
Loading

0 comments on commit eab7fc2

Please sign in to comment.