diff --git a/src/lib/BitcoinECC/BitcoinECC.py b/src/lib/BitcoinECC/BitcoinECC.py deleted file mode 100644 index 6f481132..00000000 --- a/src/lib/BitcoinECC/BitcoinECC.py +++ /dev/null @@ -1,467 +0,0 @@ -# By: HurlSly -# Source: https://github.com/HurlSly/Python/blob/master/BitcoinECC.py -# Modified: random number generator in def GeneratePrivateKey(self): - -import random -import hashlib -import os - -class GaussInt: - #A class for the Gauss integers of the form a + b sqrt(n) where a,b are integers. - #n can be positive or negative. - def __init__(self,x,y,n,p=0): - if p: - self.x=x%p - self.y=y%p - self.n=n%p - else: - self.x=x - self.y=y - self.n=n - - self.p=p - - def __add__(self,b): - return GaussInt(self.x+b.x,self.y+b.y,self.n,self.p) - - def __sub__(self,b): - return GaussInt(self.x-b.x,self.y-b.y,self.n,self.p) - - def __mul__(self,b): - return GaussInt(self.x*b.x+self.n*self.y*b.y,self.x*b.y+self.y*b.x,self.n,self.p) - - def __div__(self,b): - return GaussInt((self.x*b.x-self.n*self.y*b.y)/(b.x*b.x-self.n*b.y*b.y),(-self.x*b.y+self.y*b.x)/(b.x*b.x-self.n*b.y*b.y),self.n,self.p) - - def __eq__(self,b): - return self.x==b.x and self.y==b.y - - def __repr__(self): - if self.p: - return "%s+%s (%d,%d)"%(self.x,self.y,self.n,self.p) - else: - return "%s+%s (%d)"%(self.x,self.y,self.n) - - def __pow__(self,n): - b=Base(n,2) - t=GaussInt(1,0,self.n) - while b: - t=t*t - if b.pop(): - t=self*t - - return t - - def Inv(self): - return GaussInt(self.x/(self.x*self.x-self.n*self.y*self.y),-self.y/(self.x*self.x-self.n*self.y*self.y),self.n,self.p) - -def Cipolla(a,p): - #Find a square root of a modulo p using the algorithm of Cipolla - b=0 - while pow((b*b-a)%p,(p-1)/2,p)==1: - b+=1 - - return (GaussInt(b,1,b**2-a,p)**((p+1)/2)).x - -def Base(n,b): - #Decompose n in base b - l=[] - while n: - l.append(n%b) - n/=b - - return l - -def InvMod(a,n): - #Find the inverse mod n of a. - #Use the Extended Euclides Algorithm. - m=[] - - s=n - while n: - m.append(a/n) - (a,n)=(n,a%n) - - u=1 - v=0 - while m: - (u,v)=(v,u-m.pop()*v) - - return u%s - -def b58encode(v): - #Encode a byte string to the Base58 - digit="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" - base=len(digit) - val=0 - for c in v: - val*=256 - val+=ord(c) - - result="" - while val: - (val,mod)=divmod(val,base) - result=digit[mod]+result - - pad=0 - for c in v: - if c=="\0": - pad+=1 - else: - break - - return (digit[0]*pad)+result - -def b58decode(v): - #Decode a Base58 string to byte string - digit="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" - base=len(digit) - val=0 - for c in v: - val*=base - val+=digit.find(c) - - result="" - while val: - (val,mod)=divmod(val,256) - result=chr(mod)+result - - pad=0 - for c in v: - if c==digit[0]: - pad+=1 - else: - break - - result="\0"*pad+result - - return result - -def Byte2Hex(b): - #Convert a byte string to hex number - out="" - for x in b: - y=hex(ord(x))[2:] - if len(y)==1: - y="0"+y - out+="%2s"%y - - return out - -def Int2Byte(n,b): - #Convert a integer to a byte string of length b - out="" - - for i in range(b): - (n,m)=divmod(n,256) - out=chr(m)+out - - return out - -class EllipticCurvePoint: - #Main class - #It is an point on an Elliptic Curve - - def __init__(self,x,a,b,p,n=0): - #We store the coordinate in x and the elliptic curbe parameter. - #x is of length 3. This is the 3 projective coordinates of the point. - self.x=x[:] - self.a=a - self.b=b - self.p=p - self.n=n - - def EqualProj(self,y): - #Does y equals self ? - #It computes self cross product with y and check if the result is 0. - return self.x[0]*y.x[1]==self.x[1]*y.x[0] and self.x[1]*y.x[2]==self.x[2]*y.x[1] and self.x[2]*y.x[0]==self.x[0]*y.x[2] - - def __add__(self,y): - #The main function to add self and y - #It uses the formulas I derived in projective coordinates. - #Projectives coordinates are more performant than the usual (x,y) coordinates - #because it we don't need to compute inverse mod p, which is faster. - z=EllipticCurvePoint([0,0,0],self.a,self.b,self.p) - - if self.EqualProj(y): - d=(2*self.x[1]*self.x[2])%self.p - d3=pow(d,3,self.p) - n=(3*pow(self.x[0],2,self.p)+self.a*pow(self.x[2],2,self.p))%self.p - - z.x[0]=(pow(n,2,self.p)*d*self.x[2]-2*d3*self.x[0])%self.p - z.x[1]=(3*self.x[0]*n*pow(d,2,self.p)-pow(n,3,self.p)*self.x[2]-self.x[1]*d3)%self.p - z.x[2]=(self.x[2]*d3)%self.p - else: - d=(y.x[0]*self.x[2]-y.x[2]*self.x[0])%self.p - d3=pow(d,3,self.p) - n=(y.x[1]*self.x[2]-self.x[1]*y.x[2])%self.p - - z.x[0]=(y.x[2]*self.x[2]*pow(n,2,self.p)*d-d3*(y.x[2]*self.x[0]+y.x[0]*self.x[2]))%self.p - z.x[1]=(pow(d,2,self.p)*n*(2*self.x[0]*y.x[2]+y.x[0]*self.x[2])-pow(n,3,self.p)*self.x[2]*y.x[2]-self.x[1]*d3*y.x[2])%self.p - z.x[2]=(self.x[2]*d3*y.x[2])%self.p - - return z - - def __mul__(self,n): - #The fast multiplication of point n times by itself. - b=Base(n,2) - t=EllipticCurvePoint(self.x,self.a,self.b,self.p) - b.pop() - while b: - t+=t - if b.pop(): - t+=self - - return t - - def __repr__(self): - #print a point in (x,y) coordinate. - return "x=%d\ny=%d\n"%((self.x[0]*InvMod(self.x[2],self.p))%self.p,(self.x[1]*InvMod(self.x[2],self.p))%self.p) - - def __eq__(self,x): - #Does self==x ? - return self.x==x.x and self.a==x.a and self.b==x.b and self.p==x.p - - def __ne__(self,x): - #Does self!=x ? - return self.x!=x.x or self.a!=x.a or self.b!=x.b or self.p!=x.p - - def Check(self): - #Is self on the curve ? - return (self.x[0]**3+self.a*self.x[0]*self.x[2]**2+self.b*self.x[2]**3-self.x[1]**2*self.x[2])%self.p==0 - - def GeneratePrivateKey(self): - #Generate a private key. It's just a random number between 1 and n-1. - #Of course, this function isn't cryptographically secure. - #Don't use it to generate your key. Use a cryptographically secure source of randomness instead. - #self.d = random.randint(1,self.n-1) - self.d = random.SystemRandom().randint(1,self.n-1) # Better random fix - - def SignECDSA(self,m): - #Sign a message. The private key is self.d . - h=hashlib.new("SHA256") - h.update(m) - z=int(h.hexdigest(),16) - - r=0 - s=0 - while not r or not s: - #k=random.randint(1,self.n-1) - k=random.SystemRandom().randint(1,self.n-1) # Better random fix - R=self*k - R.Normalize() - r=R.x[0]%self.n - s=(InvMod(k,self.n)*(z+r*self.d))%self.n - - return (r,s) - - def CheckECDSA(self,sig,m): - #Check a signature (r,s) of the message m using the public key self.Q - # and the generator which is self. - #This is not the one used by Bitcoin because the public key isn't known; - # only a hash of the public key is known. See the next function. - (r,s)=sig - - h=hashlib.new("SHA256") - h.update(m) - z=int(h.hexdigest(),16) - - if self.Q.x[2]==0: - return False - if not self.Q.Check(): - return False - if (self.Q*self.n).x[2]!=0: - return False - if r<1 or r>self.n-1 or s<1 or s>self.n-1: - return False - - w=InvMod(s,self.n) - u1=(z*w)%self.n - u2=(r*w)%self.n - R=self*u1+self.Q*u2 - R.Normalize() - - return (R.x[0]-r)%self.n==0 - - def VerifyMessageFromBitcoinAddress(self,adresse,m,sig): - #Check a signature (r,s) for the message m signed by the Bitcoin - # address "addresse". - h=hashlib.new("SHA256") - h.update(m) - z=int(h.hexdigest(),16) - - (r,s)=sig - x=r - y2=(pow(x,3,self.p)+self.a*x+self.b)%self.p - y=Cipolla(y2,self.p) - - for i in range(2): - kG=EllipticCurvePoint([x,y,1],self.a,self.b,self.p,self.n) - mzG=self*((-z)%self.n) - self.Q=(kG*s+mzG)*InvMod(r,self.n) - - adr=self.BitcoinAddresFromPublicKey() - if adr==adresse: - break - y=(-y)%self.p - - if adr!=adresse: - return False - - return True - - def BitcoinAddressFromPrivate(self,pri=None): - #Transform a private key in base58 encoding to a bitcoin address. - #normal means "uncompressed". - if not pri: - print "Private Key :", - pri=raw_input() - - normal=(len(pri)==51) - pri=b58decode(pri) - - if normal: - pri=pri[1:-4] - else: - pri=pri[1:-5] - - self.d=int(Byte2Hex(pri),16) - - return self.BitcoinAddress(normal) - - def PrivateEncoding(self,normal=True): - #Encode a private key self.d to base58 encoding. - p=Int2Byte(self.d,32) - p="\80"+p - - if not normal: - p+=chr(1) - - h=hashlib.new("SHA256") - h.update(p) - s=h.digest() - - h=hashlib.new("SHA256") - h.update(s) - s=h.digest() - - cs=s[:4] - - p+=cs - p=b58encode(p) - - return p - - def BitcoinAddresFromPublicKey(self,normal=True): - #Find the bitcoin address from the public key self.Q - #We do normalization to go from the projective coordinates to the usual - # (x,y) coordinates. - self.Q.Normalize() - if normal: - pk=chr(4)+Int2Byte(self.Q.x[0],32)+Int2Byte((self.Q.x[1])%self.p,32) - else: - if self.Q.x[1]%2==0: - pk=chr(2)+Int2Byte(self.Q.x[0],32) - else: - pk=chr(3)+Int2Byte(self.Q.x[0],32) - - version=chr(0) - - h=hashlib.new("SHA256") - h.update(pk) - s=h.digest() - - h=hashlib.new("RIPEMD160") - h.update(s) - kh=version+h.digest() - - h=hashlib.new("SHA256") - h.update(kh) - cs=h.digest() - - h=hashlib.new("SHA256") - h.update(cs) - cs=h.digest()[:4] - - adr=b58encode(kh+cs) - - return adr - - def BitcoinAddress(self,normal=True): - #Computes a bitcoin address given the private key self.d. - self.Q=self*self.d - - return self.BitcoinAddresFromPublicKey(normal) - - def BitcoinAddressGenerator(self,k,filename): - #Generate Bitcoin address and write them in the filename in the multibit format. - #Change the date as you like. - f=open(filename,"w") - for i in range(k): - self.GeneratePrivateKey() - adr=self.BitcoinAddress() - p=self.PrivateEncoding() - f.write("#%s\n%s 2014-01-30T12:00:00Z\n"%(adr,p)) - - #print hex(self.d) - print adr,p - - f.close() - - def TestSign(self): - #Test signature - self.GeneratePrivateKey() - self.Q=self*self.d - m="Hello World" - adresse=self.BitcoinAddresFromPublicKey() - (r,s)=self.SignECDSA(m) - - m="Hello World" - print self.VerifyMessageFromBitcoinAddress(adresse,m,r,s) - - def Normalize(self): - #Transform projective coordinates of self to the usual (x,y) coordinates. - if self.x[2]: - self.x[0]=(self.x[0]*InvMod(self.x[2],self.p))%self.p - self.x[1]=(self.x[1]*InvMod(self.x[2],self.p))%self.p - self.x[2]=1 - elif self.x[1]: - self.x[0]=(self.x[0]*InvMod(self.x[1],self.p))%self.p - self.x[1]=1 - elif self.x[0]: - self.x[0]=1 - else: - raise Exception - -def Bitcoin(): - #Create the Bitcoin elliptiv curve - a=0 - b=7 - p=2**256-2**32-2**9-2**8-2**7-2**6-2**4-1 - - #Create the generator G of the Bitcoin elliptic curve, with is order n. - Gx=int("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798",16) - Gy=int("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8",16) - n =int("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141",16) - - #Create the generator - return EllipticCurvePoint([Gx,Gy,1],a,b,p,n) - - -if __name__ == "__main__": - bitcoin=Bitcoin() - - #Generate the public key from the private one - print bitcoin.BitcoinAddressFromPrivate("23DKRBLkeDbcSaddsMYLAHXhanPmGwkWAhSPVGbspAkc72Hw9BdrDF") - print bitcoin.BitcoinAddress() - - #Print the bitcoin address of the public key generated at the previous line - adr=bitcoin.BitcoinAddresFromPublicKey() - print adr - - #Sign a message with the current address - m="Hello World" - sig=bitcoin.SignECDSA("Hello World") - #Verify the message using only the bitcoin adress, the signature and the message. - #Not using the public key as it is not needed. - print bitcoin.VerifyMessageFromBitcoinAddress(adr,m,sig) diff --git a/src/lib/BitcoinECC/__init__.py b/src/lib/BitcoinECC/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/lib/BitcoinECC/newBitcoinECC.py b/src/lib/BitcoinECC/newBitcoinECC.py deleted file mode 100644 index 65b64880..00000000 --- a/src/lib/BitcoinECC/newBitcoinECC.py +++ /dev/null @@ -1,461 +0,0 @@ -import random -import hashlib -import base64 -import math - -class GaussInt: - def __init__(self,x,y,n,p=0): - if p: - self.x=x%p - self.y=y%p - self.n=n%p - else: - self.x=x - self.y=y - self.n=n - - self.p=p - - def __add__(self,b): - return GaussInt(self.x+b.x,self.y+b.y,self.n,self.p) - - def __sub__(self,b): - return GaussInt(self.x-b.x,self.y-b.y,self.n,self.p) - - def __mul__(self,b): - return GaussInt(self.x*b.x+self.n*self.y*b.y,self.x*b.y+self.y*b.x,self.n,self.p) - - def __div__(self,b): - return GaussInt((self.x*b.x-self.n*self.y*b.y)/(b.x*b.x-self.n*b.y*b.y),(-self.x*b.y+self.y*b.x)/(b.x*b.x-self.n*b.y*b.y),self.n,self.p) - - def __eq__(self,b): - return self.x==b.x and self.y==b.y - - def __repr__(self): - if self.p: - return "%s+%s (%d,%d)"%(self.x,self.y,self.n,self.p) - else: - return "%s+%s (%d)"%(self.x,self.y,self.n) - - def __pow__(self,n): - b=Base(n,2) - t=GaussInt(1,0,self.n) - while b: - t=t*t - if b.pop(): - t=self*t - - return t - - def Inv(self): - return GaussInt(self.x/(self.x*self.x-self.n*self.y*self.y),-self.y/(self.x*self.x-self.n*self.y*self.y),self.n,self.p) - - def Eval(self): - return self.x.Eval()+self.y.Eval()*math.sqrt(self.n) - -def Cipolla(a,p): - b=0 - while pow((b*b-a)%p,(p-1)/2,p)==1: - b+=1 - - return (GaussInt(b,1,b**2-a,p)**((p+1)/2)).x - -def InvMod(a,n): - m=[] - - s=n - while n: - m.append(a/n) - (a,n)=(n,a%n) - - u=1 - v=0 - while m: - (u,v)=(v,u-m.pop()*v) - - return u%s - -def Base(n,b): - l=[] - while n: - l.append(n%b) - n/=b - - return l - -def MsgMagic(message): - return "\x18Bitcoin Signed Message:\n"+chr(len(message))+message - -def Hash(m,method): - h=hashlib.new(method) - h.update(m) - - return h.digest() - -def b58encode(v): - #Encode a byte string to the Base58 - digit="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" - base=len(digit) - val=0 - for c in v: - val*=256 - val+=ord(c) - - result="" - while val: - (val,mod)=divmod(val,base) - result=digit[mod]+result - - pad=0 - for c in v: - if c=="\x00": - pad+=1 - else: - break - - return (digit[0]*pad)+result - -def b58decode(v): - #Decode a Base58 string to byte string - digit="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" - base=len(digit) - val=0 - for c in v: - val*=base - val+=digit.find(c) - - result="" - while val: - (val,mod)=divmod(val,256) - result=chr(mod)+result - - pad=0 - for c in v: - if c==digit[0]: - pad+=1 - else: - break - - return "\x00"*pad+result - -def Byte2Int(b): - n=0 - for x in b: - n*=256 - n+=ord(x) - - return n - -def Byte2Hex(b): - #Convert a byte string to hex number - out="" - for x in b: - y=hex(ord(x))[2:] - if len(y)==1: - y="0"+y - out+="%2s"%y - - return out - -def Int2Byte(n,b): - #Convert a integer to a byte string of length b - out="" - - for _ in range(b): - (n,m)=divmod(n,256) - out=chr(m)+out - - return out - -class EllipticCurvePoint: - #Main class - #It's a point on an Elliptic Curve - - def __init__(self,x,a,b,p,n=0): - #We store the coordinate in x and the elliptic curve parameter. - #x is of length 3. This is the 3 projective coordinates of the point. - self.x=x[:] - self.a=a - self.b=b - self.p=p - self.n=n - - def __add__(self,y): - #The main function to add self and y - #It uses the formulas I derived in projective coordinates. - #Projectives coordinates are more efficient than the usual (x,y) coordinates - #because we don't need to compute inverse mod p, which is faster. - z=EllipticCurvePoint([0,0,0],self.a,self.b,self.p) - - if self==y: - d=(2*self.x[1]*self.x[2])%self.p - d3=pow(d,3,self.p) - n=(3*pow(self.x[0],2,self.p)+self.a*pow(self.x[2],2,self.p))%self.p - - z.x[0]=(pow(n,2,self.p)*d*self.x[2]-2*d3*self.x[0])%self.p - z.x[1]=(3*self.x[0]*n*pow(d,2,self.p)-pow(n,3,self.p)*self.x[2]-self.x[1]*d3)%self.p - z.x[2]=(self.x[2]*d3)%self.p - else: - d=(y.x[0]*self.x[2]-y.x[2]*self.x[0])%self.p - d3=pow(d,3,self.p) - n=(y.x[1]*self.x[2]-self.x[1]*y.x[2])%self.p - - z.x[0]=(y.x[2]*self.x[2]*pow(n,2,self.p)*d-d3*(y.x[2]*self.x[0]+y.x[0]*self.x[2]))%self.p - z.x[1]=(pow(d,2,self.p)*n*(2*self.x[0]*y.x[2]+y.x[0]*self.x[2])-pow(n,3,self.p)*self.x[2]*y.x[2]-self.x[1]*d3*y.x[2])%self.p - z.x[2]=(self.x[2]*d3*y.x[2])%self.p - - return z - - def __mul__(self,n): - #The fast multiplication of point n times by itself. - b=Base(n,2) - t=EllipticCurvePoint(self.x,self.a,self.b,self.p) - b.pop() - while b: - t+=t - if b.pop(): - t+=self - - return t - - def __repr__(self): - #print a point in (x,y) coordinate. - return "x=%d\ny=%d\n"%((self.x[0]*InvMod(self.x[2],self.p))%self.p,(self.x[1]*InvMod(self.x[2],self.p))%self.p) - - def __eq__(self,y): - #Does self==y ? - #It computes self cross product with x and check if the result is 0. - return self.x[0]*y.x[1]==self.x[1]*y.x[0] and self.x[1]*y.x[2]==self.x[2]*y.x[1] and self.x[2]*y.x[0]==self.x[0]*y.x[2] and self.a==y.a and self.b==y.b and self.p==y.p - - def __ne__(self,y): - #Does self!=x ? - return not (self == y) - - def Normalize(self): - #Transform projective coordinates of self to the usual (x,y) coordinates. - if self.x[2]: - self.x[0]=(self.x[0]*InvMod(self.x[2],self.p))%self.p - self.x[1]=(self.x[1]*InvMod(self.x[2],self.p))%self.p - self.x[2]=1 - elif self.x[1]: - self.x[0]=(self.x[0]*InvMod(self.x[1],self.p))%self.p - self.x[1]=1 - elif self.x[0]: - self.x[0]=1 - else: - raise Exception - - def Check(self): - #Is self on the curve ? - return (self.x[0]**3+self.a*self.x[0]*self.x[2]**2+self.b*self.x[2]**3-self.x[1]**2*self.x[2])%self.p==0 - - - def CryptAddr(self,filename,password,Address): - txt="" - for tag in Address: - (addr,priv)=Address[tag] - if priv: - txt+="%s\t%s\t%s\n"%(tag,addr,priv) - else: - txt+="%s\t%s\t\n"%(tag,addr) - - txt+="\x00"*(15-(len(txt)-1)%16) - - password+="\x00"*(15-(len(password)-1)%16) - crypt=twofish.Twofish(password).encrypt(txt) - - f=open(filename,"wb") - f.write(crypt) - f.close() - - def GenerateD(self): - #Generate a private key. It's just a random number between 1 and n-1. - #Of course, this function isn't cryptographically secure. - #Don't use it to generate your key. Use a cryptographically secure source of randomness instead. - #return random.randint(1,self.n-1) - return random.SystemRandom().randint(1,self.n-1) # Better random fix - - def CheckECDSA(self,sig,message,Q): - #Check a signature (r,s) of the message m using the public key self.Q - # and the generator which is self. - #This is not the one used by Bitcoin because the public key isn't known; - # only a hash of the public key is known. See the function VerifyMessageFromAddress. - (r,s)=sig - - if Q.x[2]==0: - return False - if not Q.Check(): - return False - if (Q*self.n).x[2]!=0: - return False - if r<1 or r>self.n-1 or s<1 or s>self.n-1: - return False - - z=Byte2Int(Hash(Hash(MsgMagic(message),"SHA256"),"SHA256")) - - w=InvMod(s,self.n) - u1=(z*w)%self.n - u2=(r*w)%self.n - R=self*u1+Q*u2 - R.Normalize() - - return (R.x[0]-r)%self.n==0 - - def SignMessage(self,message,priv): - #Sign a message. The private key is self.d. - (d,uncompressed)=self.DFromPriv(priv) - - z=Byte2Int(Hash(Hash(MsgMagic(message),"SHA256"),"SHA256")) - - r=0 - s=0 - while not r or not s: - #k=random.randint(1,self.n-1) - k=random.SystemRandom().randint(1,self.n-1) # Better random fix - R=self*k - R.Normalize() - r=R.x[0]%self.n - s=(InvMod(k,self.n)*(z+r*d))%self.n - - val=27 - if not uncompressed: - val+=4 - - return base64.standard_b64encode(chr(val)+Int2Byte(r,32)+Int2Byte(s,32)) - - def VerifyMessageFromAddress(self,addr,message,sig): - #Check a signature (r,s) for the message m signed by the Bitcoin - # address "addr". - - sign=base64.standard_b64decode(sig) - (r,s)=(Byte2Int(sign[1:33]),Byte2Int(sign[33:65])) - - z=Byte2Int(Hash(Hash(MsgMagic(message),"SHA256"),"SHA256")) - - val=ord(sign[0]) - if val<27 or val>=35: - return False - - if val>=31: - uncompressed=False - val-=4 - else: - uncompressed=True - - x=r - y2=(pow(x,3,self.p) + self.a*x + self.b) % self.p - y=Cipolla(y2,self.p) - - for _ in range(2): - kG=EllipticCurvePoint([x,y,1],self.a,self.b,self.p,self.n) - mzG=self*((-z)%self.n) - Q=(kG*s+mzG)*InvMod(r,self.n) - - if self.AddressFromPublicKey(Q,uncompressed)==addr: - return True - - y=self.p-y - - return False - - def AddressFromPrivate(self,priv): - #Transform a private key to a bitcoin address. - (d,uncompressed)=self.DFromPriv(priv) - - return self.AddressFromD(d,uncompressed) - - def PrivFromD(self,d,uncompressed): - #Encode a private key self.d to base58 encoding. - p=Int2Byte(d,32) - p="\x80"+p - - if not uncompressed: - p+=chr(1) - - cs=Hash(Hash(p,"SHA256"),"SHA256")[:4] - - return b58encode(p+cs) - - def DFromPriv(self,priv): - uncompressed=(len(priv)==51) - priv=b58decode(priv) - - if uncompressed: - priv=priv[:-4] - else: - priv=priv[:-5] - - return (Byte2Int(priv[1:]),uncompressed) - - def AddressFromPublicKey(self,Q,uncompressed): - #Find the bitcoin address from the public key self.Q - #We do normalization to go from the projective coordinates to the usual - # (x,y) coordinates. - Q.Normalize() - if uncompressed: - pk=chr(4)+Int2Byte(Q.x[0],32)+Int2Byte(Q.x[1],32) - else: - pk=chr(2+Q.x[1]%2)+Int2Byte(Q.x[0],32) - - kh=chr(0)+Hash(Hash(pk,"SHA256"),"RIPEMD160") - cs=Hash(Hash(kh,"SHA256"),"SHA256")[:4] - - return b58encode(kh+cs) - - def AddressFromD(self,d,uncompressed): - #Computes a bitcoin address given the private key self.d. - return self.AddressFromPublicKey(self*d,uncompressed) - - def IsValid(self,addr): - adr=b58decode(addr) - kh=adr[:-4] - cs=adr[-4:] - - verif=Hash(Hash(kh,"SHA256"),"SHA256")[:4] - - return cs==verif - - def AddressGenerator(self,k,uncompressed=True): - #Generate Bitcoin address and write them in the multibit format. - #Change the date as you like. - liste={} - for i in range(k): - d=self.GenerateD() - addr=self.AddressFromD(d,uncompressed) - priv=self.PrivFromD(d,uncompressed) - liste[i]=[addr,priv] - print "%s %s"%(addr, priv) - - return liste - -def Bitcoin(): - a=0 - b=7 - p=2**256-2**32-2**9-2**8-2**7-2**6-2**4-1 - Gx=int("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798",16) - Gy=int("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8",16) - n=int("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141",16) - - return EllipticCurvePoint([Gx,Gy,1],a,b,p,n) - -def main(): - bitcoin=Bitcoin() - - #Generate an adress from the private key - privkey = "PrivatekeyinBase58" - adr = bitcoin.AddressFromPrivate(privkey) - print "Address : ", adr - - #Sign a message with the current address - m="Hello World" - sig=bitcoin.SignMessage("Hello World", privkey) - #Verify the message using only the bitcoin adress, the signature and the message. - #Not using the public key as it is not needed. - if bitcoin.VerifyMessageFromAddress(adr,m,sig): - print "Message verified" - - #Generate some addresses - print "Here are some adresses and associated private keys" - bitcoin.AddressGenerator(10) - -if __name__ == "__main__": main() diff --git a/src/lib/PySocks/LICENSE b/src/lib/PySocks/LICENSE deleted file mode 100644 index 04b6b1f3..00000000 --- a/src/lib/PySocks/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -Copyright 2006 Dan-Haim. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. -3. Neither the name of Dan Haim nor the names of his contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY DAN HAIM "AS IS" AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO -EVENT SHALL DAN HAIM OR HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA -OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMANGE. diff --git a/src/lib/PySocks/README.md b/src/lib/PySocks/README.md deleted file mode 100644 index 65419240..00000000 --- a/src/lib/PySocks/README.md +++ /dev/null @@ -1,299 +0,0 @@ -PySocks -======= - -Updated version of SocksiPy. Many old bugs fixed, and overall code cleanup. - -Acts as a drop-in replacement to the socket module. - ----------------- - -Features -======== - -* Fully supports Python 2.6 - 3.4 - -* UDP support - -* SocksiPyHandler, courtesy e000, was also added as an example of how this module can be used with urllib2. See example code in sockshandler.py. `pip install` and `setup.py install` will automatically install the `sockshandler` module. - -* Bugs in the original SocksiPy were fixed, including two that could lead to infinite hanging when communicating with bad proxy servers. - -* urllib3, which powers the requests module, is working on integrating SOCKS proxy support based on this branch - -* `SOCKS5`, `SOCKS4`, and `HTTP` are now aliases for `PROXY_TYPE_SOCKS5`, `PROXY_TYPE_SOCKS4`, and `PROXY_TYPE_HTTP` - -* Tests added - -* Various style and performance improvements; codebase simplified - -* Actively maintained - -Installation -============ - - pip install PySocks - -Or download the tarball / `git clone` and... - - python setup.py install - -These will install both the `socks` and `sockshandler` modules. - -Alternatively, include just `socks.py` in your project. - --------------------------------------------- - -*Warning:* PySocks/SocksiPy only supports HTTP proxies that use CONNECT tunneling. Certain HTTP proxies may not work with this library. If you wish to use HTTP proxies (and not SOCKS proxies), it is recommended that you rely on your HTTP client's native proxy support (`proxies` dict for `requests`, or `urllib2.ProxyHandler` for `urllib2`) instead. - --------------------------------------------- - -Usage -===== - -## Example ## - - import socks - - s = socks.socksocket() - - s.set_proxy(socks.SOCKS5, "localhost") # SOCKS4 and SOCKS5 use port 1080 by default - # Or - s.set_proxy(socks.SOCKS4, "localhost", 4444) - # Or - s.set_proxy(socks.HTTP, "5.5.5.5", 8888) - - # Can be treated identical to a regular socket object - s.connect(("www.test.com", 80)) - s.sendall("GET / ...") - print s.recv(4096) - - -To monkeypatch the entire standard library with a single default proxy: - - import socket - import socks - import urllib2 - - socks.set_default_proxy(socks.SOCKS5, "localhost") - socket.socket = socks.socksocket - - urllib2.urlopen("http://...") # All requests will pass through the SOCKS proxy - -Note that monkeypatching may not work for all standard modules or for all third party modules, and generally isn't recommended. - --------------------------------------------- - -Original SocksiPy README attached below, amended to reflect API changes. - --------------------------------------------- - -SocksiPy - version 1.5.0 - -A Python SOCKS module. - -(C) 2006 Dan-Haim. All rights reserved. - -See LICENSE file for details. - - -*WHAT IS A SOCKS PROXY?* - -A SOCKS proxy is a proxy server at the TCP level. In other words, it acts as -a tunnel, relaying all traffic going through it without modifying it. -SOCKS proxies can be used to relay traffic using any network protocol that -uses TCP. - -*WHAT IS SOCKSIPY?* - -This Python module allows you to create TCP connections through a SOCKS -proxy without any special effort. -It also supports relaying UDP packets with a SOCKS5 proxy. - -*PROXY COMPATIBILITY* - -SocksiPy is compatible with three different types of proxies: - -1. SOCKS Version 4 (SOCKS4), including the SOCKS4a extension. -2. SOCKS Version 5 (SOCKS5). -3. HTTP Proxies which support tunneling using the CONNECT method. - -*SYSTEM REQUIREMENTS* - -Being written in Python, SocksiPy can run on any platform that has a Python -interpreter and TCP/IP support. -This module has been tested with Python 2.3 and should work with greater versions -just as well. - - -INSTALLATION -------------- - -Simply copy the file "socks.py" to your Python's `lib/site-packages` directory, -and you're ready to go. [Editor's note: it is better to use `python setup.py install` for PySocks] - - -USAGE ------- - -First load the socks module with the command: - - >>> import socks - >>> - -The socks module provides a class called `socksocket`, which is the base to all of the module's functionality. - -The `socksocket` object has the same initialization parameters as the normal socket -object to ensure maximal compatibility, however it should be noted that `socksocket` will only function with family being `AF_INET` and -type being either `SOCK_STREAM` or `SOCK_DGRAM`. -Generally, it is best to initialize the `socksocket` object with no parameters - - >>> s = socks.socksocket() - >>> - -The `socksocket` object has an interface which is very similiar to socket's (in fact -the `socksocket` class is derived from socket) with a few extra methods. -To select the proxy server you would like to use, use the `set_proxy` method, whose -syntax is: - - set_proxy(proxy_type, addr[, port[, rdns[, username[, password]]]]) - -Explanation of the parameters: - -`proxy_type` - The type of the proxy server. This can be one of three possible -choices: `PROXY_TYPE_SOCKS4`, `PROXY_TYPE_SOCKS5` and `PROXY_TYPE_HTTP` for SOCKS4, -SOCKS5 and HTTP servers respectively. `SOCKS4`, `SOCKS5`, and `HTTP` are all aliases, respectively. - -`addr` - The IP address or DNS name of the proxy server. - -`port` - The port of the proxy server. Defaults to 1080 for socks and 8080 for http. - -`rdns` - This is a boolean flag than modifies the behavior regarding DNS resolving. -If it is set to True, DNS resolving will be preformed remotely, on the server. -If it is set to False, DNS resolving will be preformed locally. Please note that -setting this to True with SOCKS4 servers actually use an extension to the protocol, -called SOCKS4a, which may not be supported on all servers (SOCKS5 and http servers -always support DNS). The default is True. - -`username` - For SOCKS5 servers, this allows simple username / password authentication -with the server. For SOCKS4 servers, this parameter will be sent as the userid. -This parameter is ignored if an HTTP server is being used. If it is not provided, -authentication will not be used (servers may accept unauthenticated requests). - -`password` - This parameter is valid only for SOCKS5 servers and specifies the -respective password for the username provided. - -Example of usage: - - >>> s.set_proxy(socks.SOCKS5, "socks.example.com") # uses default port 1080 - >>> s.set_proxy(socks.SOCKS4, "socks.test.com", 1081) - -After the set_proxy method has been called, simply call the connect method with the -traditional parameters to establish a connection through the proxy: - - >>> s.connect(("www.sourceforge.net", 80)) - >>> - -Connection will take a bit longer to allow negotiation with the proxy server. -Please note that calling connect without calling `set_proxy` earlier will connect -without a proxy (just like a regular socket). - -Errors: Any errors in the connection process will trigger exceptions. The exception -may either be generated by the underlying socket layer or may be custom module -exceptions, whose details follow: - -class `ProxyError` - This is a base exception class. It is not raised directly but -rather all other exception classes raised by this module are derived from it. -This allows an easy way to catch all proxy-related errors. It descends from `IOError`. - -All `ProxyError` exceptions have an attribute `socket_err`, which will contain either a -caught `socket.error` exception, or `None` if there wasn't any. - -class `GeneralProxyError` - When thrown, it indicates a problem which does not fall -into another category. - -* `Sent invalid data` - This error means that unexpected data has been received from -the server. The most common reason is that the server specified as the proxy is -not really a SOCKS4/SOCKS5/HTTP proxy, or maybe the proxy type specified is wrong. - -* `Connection closed unexpectedly` - The proxy server unexpectedly closed the connection. -This may indicate that the proxy server is experiencing network or software problems. - -* `Bad proxy type` - This will be raised if the type of the proxy supplied to the -set_proxy function was not one of `SOCKS4`/`SOCKS5`/`HTTP`. - -* `Bad input` - This will be raised if the `connect()` method is called with bad input -parameters. - -class `SOCKS5AuthError` - This indicates that the connection through a SOCKS5 server -failed due to an authentication problem. - -* `Authentication is required` - This will happen if you use a SOCKS5 server which -requires authentication without providing a username / password at all. - -* `All offered authentication methods were rejected` - This will happen if the proxy -requires a special authentication method which is not supported by this module. - -* `Unknown username or invalid password` - Self descriptive. - -class `SOCKS5Error` - This will be raised for SOCKS5 errors which are not related to -authentication. -The parameter is a tuple containing a code, as given by the server, -and a description of the -error. The possible errors, according to the RFC, are: - -* `0x01` - General SOCKS server failure - If for any reason the proxy server is unable to -fulfill your request (internal server error). -* `0x02` - connection not allowed by ruleset - If the address you're trying to connect to -is blacklisted on the server or requires authentication. -* `0x03` - Network unreachable - The target could not be contacted. A router on the network -had replied with a destination net unreachable error. -* `0x04` - Host unreachable - The target could not be contacted. A router on the network -had replied with a destination host unreachable error. -* `0x05` - Connection refused - The target server has actively refused the connection -(the requested port is closed). -* `0x06` - TTL expired - The TTL value of the SYN packet from the proxy to the target server -has expired. This usually means that there are network problems causing the packet -to be caught in a router-to-router "ping-pong". -* `0x07` - Command not supported - For instance if the server does not support UDP. -* `0x08` - Address type not supported - The client has provided an invalid address type. -When using this module, this error should not occur. - -class `SOCKS4Error` - This will be raised for SOCKS4 errors. The parameter is a tuple -containing a code and a description of the error, as given by the server. The -possible error, according to the specification are: - -* `0x5B` - Request rejected or failed - Will be raised in the event of an failure for any -reason other then the two mentioned next. -* `0x5C` - request rejected because SOCKS server cannot connect to identd on the client - -The Socks server had tried an ident lookup on your computer and has failed. In this -case you should run an identd server and/or configure your firewall to allow incoming -connections to local port 113 from the remote server. -* `0x5D` - request rejected because the client program and identd report different user-ids - -The Socks server had performed an ident lookup on your computer and has received a -different userid than the one you have provided. Change your userid (through the -username parameter of the set_proxy method) to match and try again. - -class `HTTPError` - This will be raised for HTTP errors. The message will contain -the HTTP status code and provided error message. - -After establishing the connection, the object behaves like a standard socket. -Methods like `makefile()` and `settimeout()` should behave just like regular sockets. -Call the `close()` method to close the connection. - -In addition to the `socksocket` class, an additional function worth mentioning is the -`set_default_proxy` function. The parameters are the same as the `set_proxy` method. -This function will set default proxy settings for newly created `socksocket` objects, -in which the proxy settings haven't been changed via the `set_proxy` method. -This is quite useful if you wish to force 3rd party modules to use a SOCKS proxy, -by overriding the socket object. -For example: - - >>> socks.set_default_proxy(socks.SOCKS5, "socks.example.com") - >>> socket.socket = socks.socksocket - >>> urllib.urlopen("http://www.sourceforge.net/") - - -PROBLEMS ---------- - -Please open a GitHub issue at https://github.com/Anorov/PySocks diff --git a/src/lib/PySocks/__init__.py b/src/lib/PySocks/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/lib/PySocks/setup.py b/src/lib/PySocks/setup.py deleted file mode 100644 index 9db0f3d2..00000000 --- a/src/lib/PySocks/setup.py +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env python -from distutils.core import setup - -VERSION = "1.5.3" - -setup( - name = "PySocks", - version = VERSION, - description = "A Python SOCKS client module. See https://github.com/Anorov/PySocks for more information.", - url = "https://github.com/Anorov/PySocks", - license = "BSD", - author = "Anorov", - author_email = "anorov.vorona@gmail.com", - keywords = ["socks", "proxy"], - py_modules=["socks", "sockshandler"] -) - diff --git a/src/lib/PySocks/socks.py b/src/lib/PySocks/socks.py deleted file mode 100644 index ad1e9780..00000000 --- a/src/lib/PySocks/socks.py +++ /dev/null @@ -1,699 +0,0 @@ -""" -SocksiPy - Python SOCKS module. -Version 1.5.3 - -Copyright 2006 Dan-Haim. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. -3. Neither the name of Dan Haim nor the names of his contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY DAN HAIM "AS IS" AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO -EVENT SHALL DAN HAIM OR HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA -OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMANGE. - - -This module provides a standard socket-like interface for Python -for tunneling connections through SOCKS proxies. - -=============================================================================== - -Minor modifications made by Christopher Gilbert (http://motomastyle.com/) -for use in PyLoris (http://pyloris.sourceforge.net/) - -Minor modifications made by Mario Vilas (http://breakingcode.wordpress.com/) -mainly to merge bug fixes found in Sourceforge - -Modifications made by Anorov (https://github.com/Anorov) --Forked and renamed to PySocks --Fixed issue with HTTP proxy failure checking (same bug that was in the old ___recvall() method) --Included SocksiPyHandler (sockshandler.py), to be used as a urllib2 handler, - courtesy of e000 (https://github.com/e000): https://gist.github.com/869791#file_socksipyhandler.py --Re-styled code to make it readable - -Aliased PROXY_TYPE_SOCKS5 -> SOCKS5 etc. - -Improved exception handling and output - -Removed irritating use of sequence indexes, replaced with tuple unpacked variables - -Fixed up Python 3 bytestring handling - chr(0x03).encode() -> b"\x03" - -Other general fixes --Added clarification that the HTTP proxy connection method only supports CONNECT-style tunneling HTTP proxies --Various small bug fixes -""" - -__version__ = "1.5.3" - -import socket -import struct -from errno import EOPNOTSUPP, EINVAL, EAGAIN -from io import BytesIO -from os import SEEK_CUR -from collections import Callable - -PROXY_TYPE_SOCKS4 = SOCKS4 = 1 -PROXY_TYPE_SOCKS5 = SOCKS5 = 2 -PROXY_TYPE_HTTP = HTTP = 3 - -PROXY_TYPES = {"SOCKS4": SOCKS4, "SOCKS5": SOCKS5, "HTTP": HTTP} -PRINTABLE_PROXY_TYPES = dict(zip(PROXY_TYPES.values(), PROXY_TYPES.keys())) - -_orgsocket = _orig_socket = socket.socket - -class ProxyError(IOError): - """ - socket_err contains original socket.error exception. - """ - def __init__(self, msg, socket_err=None): - self.msg = msg - self.socket_err = socket_err - - if socket_err: - self.msg += ": {0}".format(socket_err) - - def __str__(self): - return self.msg - -class GeneralProxyError(ProxyError): pass -class ProxyConnectionError(ProxyError): pass -class SOCKS5AuthError(ProxyError): pass -class SOCKS5Error(ProxyError): pass -class SOCKS4Error(ProxyError): pass -class HTTPError(ProxyError): pass - -SOCKS4_ERRORS = { 0x5B: "Request rejected or failed", - 0x5C: "Request rejected because SOCKS server cannot connect to identd on the client", - 0x5D: "Request rejected because the client program and identd report different user-ids" - } - -SOCKS5_ERRORS = { 0x01: "General SOCKS server failure", - 0x02: "Connection not allowed by ruleset", - 0x03: "Network unreachable", - 0x04: "Host unreachable", - 0x05: "Connection refused", - 0x06: "TTL expired", - 0x07: "Command not supported, or protocol error", - 0x08: "Address type not supported" - } - -DEFAULT_PORTS = { SOCKS4: 1080, - SOCKS5: 1080, - HTTP: 8080 - } - -def set_default_proxy(proxy_type=None, addr=None, port=None, rdns=True, username=None, password=None): - """ - set_default_proxy(proxy_type, addr[, port[, rdns[, username, password]]]) - - Sets a default proxy which all further socksocket objects will use, - unless explicitly changed. All parameters are as for socket.set_proxy(). - """ - socksocket.default_proxy = (proxy_type, addr, port, rdns, - username.encode() if username else None, - password.encode() if password else None) - -setdefaultproxy = set_default_proxy - -def get_default_proxy(): - """ - Returns the default proxy, set by set_default_proxy. - """ - return socksocket.default_proxy - -getdefaultproxy = get_default_proxy - -def wrap_module(module): - """ - Attempts to replace a module's socket library with a SOCKS socket. Must set - a default proxy using set_default_proxy(...) first. - This will only work on modules that import socket directly into the namespace; - most of the Python Standard Library falls into this category. - """ - if socksocket.default_proxy: - module.socket.socket = socksocket - else: - raise GeneralProxyError("No default proxy specified") - -wrapmodule = wrap_module - -def create_connection(dest_pair, proxy_type=None, proxy_addr=None, - proxy_port=None, proxy_username=None, - proxy_password=None, timeout=None, - source_address=None): - """create_connection(dest_pair, *[, timeout], **proxy_args) -> socket object - - Like socket.create_connection(), but connects to proxy - before returning the socket object. - - dest_pair - 2-tuple of (IP/hostname, port). - **proxy_args - Same args passed to socksocket.set_proxy() if present. - timeout - Optional socket timeout value, in seconds. - source_address - tuple (host, port) for the socket to bind to as its source - address before connecting (only for compatibility) - """ - sock = socksocket() - if isinstance(timeout, (int, float)): - sock.settimeout(timeout) - if proxy_type is not None: - sock.set_proxy(proxy_type, proxy_addr, proxy_port, - proxy_username, proxy_password) - sock.connect(dest_pair) - return sock - -class _BaseSocket(socket.socket): - """Allows Python 2's "delegated" methods such as send() to be overridden - """ - def __init__(self, *pos, **kw): - _orig_socket.__init__(self, *pos, **kw) - - self._savedmethods = dict() - for name in self._savenames: - self._savedmethods[name] = getattr(self, name) - delattr(self, name) # Allows normal overriding mechanism to work - - _savenames = list() - -def _makemethod(name): - return lambda self, *pos, **kw: self._savedmethods[name](*pos, **kw) -for name in ("sendto", "send", "recvfrom", "recv"): - method = getattr(_BaseSocket, name, None) - - # Determine if the method is not defined the usual way - # as a function in the class. - # Python 2 uses __slots__, so there are descriptors for each method, - # but they are not functions. - if not isinstance(method, Callable): - _BaseSocket._savenames.append(name) - setattr(_BaseSocket, name, _makemethod(name)) - -class socksocket(_BaseSocket): - """socksocket([family[, type[, proto]]]) -> socket object - - Open a SOCKS enabled socket. The parameters are the same as - those of the standard socket init. In order for SOCKS to work, - you must specify family=AF_INET and proto=0. - The "type" argument must be either SOCK_STREAM or SOCK_DGRAM. - """ - - default_proxy = None - - def __init__(self, family=socket.AF_INET, type=socket.SOCK_STREAM, proto=0, _sock=None): - if type not in (socket.SOCK_STREAM, socket.SOCK_DGRAM): - msg = "Socket type must be stream or datagram, not {!r}" - raise ValueError(msg.format(type)) - - _BaseSocket.__init__(self, family, type, proto, _sock) - self._proxyconn = None # TCP connection to keep UDP relay alive - - if self.default_proxy: - self.proxy = self.default_proxy - else: - self.proxy = (None, None, None, None, None, None) - self.proxy_sockname = None - self.proxy_peername = None - - def _readall(self, file, count): - """ - Receive EXACTLY the number of bytes requested from the file object. - Blocks until the required number of bytes have been received. - """ - data = b"" - while len(data) < count: - d = file.read(count - len(data)) - if not d: - raise GeneralProxyError("Connection closed unexpectedly") - data += d - return data - - def set_proxy(self, proxy_type=None, addr=None, port=None, rdns=True, username=None, password=None): - """set_proxy(proxy_type, addr[, port[, rdns[, username[, password]]]]) - Sets the proxy to be used. - - proxy_type - The type of the proxy to be used. Three types - are supported: PROXY_TYPE_SOCKS4 (including socks4a), - PROXY_TYPE_SOCKS5 and PROXY_TYPE_HTTP - addr - The address of the server (IP or DNS). - port - The port of the server. Defaults to 1080 for SOCKS - servers and 8080 for HTTP proxy servers. - rdns - Should DNS queries be performed on the remote side - (rather than the local side). The default is True. - Note: This has no effect with SOCKS4 servers. - username - Username to authenticate with to the server. - The default is no authentication. - password - Password to authenticate with to the server. - Only relevant when username is also provided. - """ - self.proxy = (proxy_type, addr, port, rdns, - username.encode() if username else None, - password.encode() if password else None) - - setproxy = set_proxy - - def bind(self, *pos, **kw): - """ - Implements proxy connection for UDP sockets, - which happens during the bind() phase. - """ - proxy_type, proxy_addr, proxy_port, rdns, username, password = self.proxy - if not proxy_type or self.type != socket.SOCK_DGRAM: - return _orig_socket.bind(self, *pos, **kw) - - if self._proxyconn: - raise socket.error(EINVAL, "Socket already bound to an address") - if proxy_type != SOCKS5: - msg = "UDP only supported by SOCKS5 proxy type" - raise socket.error(EOPNOTSUPP, msg) - _BaseSocket.bind(self, *pos, **kw) - - # Need to specify actual local port because - # some relays drop packets if a port of zero is specified. - # Avoid specifying host address in case of NAT though. - _, port = self.getsockname() - dst = ("0", port) - - self._proxyconn = _orig_socket() - proxy = self._proxy_addr() - self._proxyconn.connect(proxy) - - UDP_ASSOCIATE = b"\x03" - _, relay = self._SOCKS5_request(self._proxyconn, UDP_ASSOCIATE, dst) - - # The relay is most likely on the same host as the SOCKS proxy, - # but some proxies return a private IP address (10.x.y.z) - host, _ = proxy - _, port = relay - _BaseSocket.connect(self, (host, port)) - self.proxy_sockname = ("0.0.0.0", 0) # Unknown - - def sendto(self, bytes, *args, **kwargs): - if self.type != socket.SOCK_DGRAM: - return _BaseSocket.sendto(self, bytes, *args, **kwargs) - if not self._proxyconn: - self.bind(("", 0)) - - address = args[-1] - flags = args[:-1] - - header = BytesIO() - RSV = b"\x00\x00" - header.write(RSV) - STANDALONE = b"\x00" - header.write(STANDALONE) - self._write_SOCKS5_address(address, header) - - sent = _BaseSocket.send(self, header.getvalue() + bytes, *flags, **kwargs) - return sent - header.tell() - - def send(self, bytes, flags=0, **kwargs): - if self.type == socket.SOCK_DGRAM: - return self.sendto(bytes, flags, self.proxy_peername, **kwargs) - else: - return _BaseSocket.send(self, bytes, flags, **kwargs) - - def recvfrom(self, bufsize, flags=0): - if self.type != socket.SOCK_DGRAM: - return _BaseSocket.recvfrom(self, bufsize, flags) - if not self._proxyconn: - self.bind(("", 0)) - - buf = BytesIO(_BaseSocket.recv(self, bufsize, flags)) - buf.seek(+2, SEEK_CUR) - frag = buf.read(1) - if ord(frag): - raise NotImplementedError("Received UDP packet fragment") - fromhost, fromport = self._read_SOCKS5_address(buf) - - if self.proxy_peername: - peerhost, peerport = self.proxy_peername - if fromhost != peerhost or peerport not in (0, fromport): - raise socket.error(EAGAIN, "Packet filtered") - - return (buf.read(), (fromhost, fromport)) - - def recv(self, *pos, **kw): - bytes, _ = self.recvfrom(*pos, **kw) - return bytes - - def close(self): - if self._proxyconn: - self._proxyconn.close() - return _BaseSocket.close(self) - - def get_proxy_sockname(self): - """ - Returns the bound IP address and port number at the proxy. - """ - return self.proxy_sockname - - getproxysockname = get_proxy_sockname - - def get_proxy_peername(self): - """ - Returns the IP and port number of the proxy. - """ - return _BaseSocket.getpeername(self) - - getproxypeername = get_proxy_peername - - def get_peername(self): - """ - Returns the IP address and port number of the destination - machine (note: get_proxy_peername returns the proxy) - """ - return self.proxy_peername - - getpeername = get_peername - - def _negotiate_SOCKS5(self, *dest_addr): - """ - Negotiates a stream connection through a SOCKS5 server. - """ - CONNECT = b"\x01" - self.proxy_peername, self.proxy_sockname = self._SOCKS5_request(self, - CONNECT, dest_addr) - - def _SOCKS5_request(self, conn, cmd, dst): - """ - Send SOCKS5 request with given command (CMD field) and - address (DST field). Returns resolved DST address that was used. - """ - proxy_type, addr, port, rdns, username, password = self.proxy - - writer = conn.makefile("wb") - reader = conn.makefile("rb", 0) # buffering=0 renamed in Python 3 - try: - # First we'll send the authentication packages we support. - if username and password: - # The username/password details were supplied to the - # set_proxy method so we support the USERNAME/PASSWORD - # authentication (in addition to the standard none). - writer.write(b"\x05\x02\x00\x02") - else: - # No username/password were entered, therefore we - # only support connections with no authentication. - writer.write(b"\x05\x01\x00") - - # We'll receive the server's response to determine which - # method was selected - writer.flush() - chosen_auth = self._readall(reader, 2) - - if chosen_auth[0:1] != b"\x05": - # Note: string[i:i+1] is used because indexing of a bytestring - # via bytestring[i] yields an integer in Python 3 - raise GeneralProxyError("SOCKS5 proxy server sent invalid data") - - # Check the chosen authentication method - - if chosen_auth[1:2] == b"\x02": - # Okay, we need to perform a basic username/password - # authentication. - writer.write(b"\x01" + chr(len(username)).encode() - + username - + chr(len(password)).encode() - + password) - writer.flush() - auth_status = self._readall(reader, 2) - if auth_status[0:1] != b"\x01": - # Bad response - raise GeneralProxyError("SOCKS5 proxy server sent invalid data") - if auth_status[1:2] != b"\x00": - # Authentication failed - raise SOCKS5AuthError("SOCKS5 authentication failed") - - # Otherwise, authentication succeeded - - # No authentication is required if 0x00 - elif chosen_auth[1:2] != b"\x00": - # Reaching here is always bad - if chosen_auth[1:2] == b"\xFF": - raise SOCKS5AuthError("All offered SOCKS5 authentication methods were rejected") - else: - raise GeneralProxyError("SOCKS5 proxy server sent invalid data") - - # Now we can request the actual connection - writer.write(b"\x05" + cmd + b"\x00") - resolved = self._write_SOCKS5_address(dst, writer) - writer.flush() - - # Get the response - resp = self._readall(reader, 3) - if resp[0:1] != b"\x05": - raise GeneralProxyError("SOCKS5 proxy server sent invalid data") - - status = ord(resp[1:2]) - if status != 0x00: - # Connection failed: server returned an error - error = SOCKS5_ERRORS.get(status, "Unknown error") - raise SOCKS5Error("{0:#04x}: {1}".format(status, error)) - - # Get the bound address/port - bnd = self._read_SOCKS5_address(reader) - return (resolved, bnd) - finally: - reader.close() - writer.close() - - def _write_SOCKS5_address(self, addr, file): - """ - Return the host and port packed for the SOCKS5 protocol, - and the resolved address as a tuple object. - """ - host, port = addr - proxy_type, _, _, rdns, username, password = self.proxy - - # If the given destination address is an IP address, we'll - # use the IPv4 address request even if remote resolving was specified. - try: - addr_bytes = socket.inet_aton(host) - file.write(b"\x01" + addr_bytes) - host = socket.inet_ntoa(addr_bytes) - except socket.error: - # Well it's not an IP number, so it's probably a DNS name. - if rdns: - # Resolve remotely - host_bytes = host.encode('idna') - file.write(b"\x03" + chr(len(host_bytes)).encode() + host_bytes) - else: - # Resolve locally - addr_bytes = socket.inet_aton(socket.gethostbyname(host)) - file.write(b"\x01" + addr_bytes) - host = socket.inet_ntoa(addr_bytes) - - file.write(struct.pack(">H", port)) - return host, port - - def _read_SOCKS5_address(self, file): - atyp = self._readall(file, 1) - if atyp == b"\x01": - addr = socket.inet_ntoa(self._readall(file, 4)) - elif atyp == b"\x03": - length = self._readall(file, 1) - addr = self._readall(file, ord(length)) - else: - raise GeneralProxyError("SOCKS5 proxy server sent invalid data") - - port = struct.unpack(">H", self._readall(file, 2))[0] - return addr, port - - def _negotiate_SOCKS4(self, dest_addr, dest_port): - """ - Negotiates a connection through a SOCKS4 server. - """ - proxy_type, addr, port, rdns, username, password = self.proxy - - writer = self.makefile("wb") - reader = self.makefile("rb", 0) # buffering=0 renamed in Python 3 - try: - # Check if the destination address provided is an IP address - remote_resolve = False - try: - addr_bytes = socket.inet_aton(dest_addr) - except socket.error: - # It's a DNS name. Check where it should be resolved. - if rdns: - addr_bytes = b"\x00\x00\x00\x01" - remote_resolve = True - else: - addr_bytes = socket.inet_aton(socket.gethostbyname(dest_addr)) - - # Construct the request packet - writer.write(struct.pack(">BBH", 0x04, 0x01, dest_port)) - writer.write(addr_bytes) - - # The username parameter is considered userid for SOCKS4 - if username: - writer.write(username) - writer.write(b"\x00") - - # DNS name if remote resolving is required - # NOTE: This is actually an extension to the SOCKS4 protocol - # called SOCKS4A and may not be supported in all cases. - if remote_resolve: - writer.write(dest_addr.encode('idna') + b"\x00") - writer.flush() - - # Get the response from the server - resp = self._readall(reader, 8) - if resp[0:1] != b"\x00": - # Bad data - raise GeneralProxyError("SOCKS4 proxy server sent invalid data") - - status = ord(resp[1:2]) - if status != 0x5A: - # Connection failed: server returned an error - error = SOCKS4_ERRORS.get(status, "Unknown error") - raise SOCKS4Error("{0:#04x}: {1}".format(status, error)) - - # Get the bound address/port - self.proxy_sockname = (socket.inet_ntoa(resp[4:]), struct.unpack(">H", resp[2:4])[0]) - if remote_resolve: - self.proxy_peername = socket.inet_ntoa(addr_bytes), dest_port - else: - self.proxy_peername = dest_addr, dest_port - finally: - reader.close() - writer.close() - - def _negotiate_HTTP(self, dest_addr, dest_port): - """ - Negotiates a connection through an HTTP server. - NOTE: This currently only supports HTTP CONNECT-style proxies. - """ - proxy_type, addr, port, rdns, username, password = self.proxy - - # If we need to resolve locally, we do this now - addr = dest_addr if rdns else socket.gethostbyname(dest_addr) - - self.sendall(b"CONNECT " + addr.encode('idna') + b":" + str(dest_port).encode() + - b" HTTP/1.1\r\n" + b"Host: " + dest_addr.encode('idna') + b"\r\n\r\n") - - # We just need the first line to check if the connection was successful - fobj = self.makefile() - status_line = fobj.readline() - fobj.close() - - if not status_line: - raise GeneralProxyError("Connection closed unexpectedly") - - try: - proto, status_code, status_msg = status_line.split(" ", 2) - except ValueError: - raise GeneralProxyError("HTTP proxy server sent invalid response") - - if not proto.startswith("HTTP/"): - raise GeneralProxyError("Proxy server does not appear to be an HTTP proxy") - - try: - status_code = int(status_code) - except ValueError: - raise HTTPError("HTTP proxy server did not return a valid HTTP status") - - if status_code != 200: - error = "{0}: {1}".format(status_code, status_msg) - if status_code in (400, 403, 405): - # It's likely that the HTTP proxy server does not support the CONNECT tunneling method - error += ("\n[*] Note: The HTTP proxy server may not be supported by PySocks" - " (must be a CONNECT tunnel proxy)") - raise HTTPError(error) - - self.proxy_sockname = (b"0.0.0.0", 0) - self.proxy_peername = addr, dest_port - - _proxy_negotiators = { - SOCKS4: _negotiate_SOCKS4, - SOCKS5: _negotiate_SOCKS5, - HTTP: _negotiate_HTTP - } - - - def connect(self, dest_pair): - """ - Connects to the specified destination through a proxy. - Uses the same API as socket's connect(). - To select the proxy server, use set_proxy(). - - dest_pair - 2-tuple of (IP/hostname, port). - """ - dest_addr, dest_port = dest_pair - - if self.type == socket.SOCK_DGRAM: - if not self._proxyconn: - self.bind(("", 0)) - dest_addr = socket.gethostbyname(dest_addr) - - # If the host address is INADDR_ANY or similar, reset the peer - # address so that packets are received from any peer - if dest_addr == "0.0.0.0" and not dest_port: - self.proxy_peername = None - else: - self.proxy_peername = (dest_addr, dest_port) - return - - proxy_type, proxy_addr, proxy_port, rdns, username, password = self.proxy - - # Do a minimal input check first - if (not isinstance(dest_pair, (list, tuple)) - or len(dest_pair) != 2 - or not dest_addr - or not isinstance(dest_port, int)): - raise GeneralProxyError("Invalid destination-connection (host, port) pair") - - - if proxy_type is None: - # Treat like regular socket object - self.proxy_peername = dest_pair - _BaseSocket.connect(self, (dest_addr, dest_port)) - return - - proxy_addr = self._proxy_addr() - - try: - # Initial connection to proxy server - _BaseSocket.connect(self, proxy_addr) - - except socket.error as error: - # Error while connecting to proxy - self.close() - proxy_addr, proxy_port = proxy_addr - proxy_server = "{0}:{1}".format(proxy_addr, proxy_port) - printable_type = PRINTABLE_PROXY_TYPES[proxy_type] - - msg = "Error connecting to {0} proxy {1}".format(printable_type, - proxy_server) - raise ProxyConnectionError(msg, error) - - else: - # Connected to proxy server, now negotiate - try: - # Calls negotiate_{SOCKS4, SOCKS5, HTTP} - negotiate = self._proxy_negotiators[proxy_type] - negotiate(self, dest_addr, dest_port) - except socket.error as error: - # Wrap socket errors - self.close() - raise GeneralProxyError("Socket error", error) - except ProxyError: - # Protocol error while negotiating with proxy - self.close() - raise - - def _proxy_addr(self): - """ - Return proxy address to connect to as tuple object - """ - proxy_type, proxy_addr, proxy_port, rdns, username, password = self.proxy - proxy_port = proxy_port or DEFAULT_PORTS.get(proxy_type) - if not proxy_port: - raise GeneralProxyError("Invalid proxy type") - return proxy_addr, proxy_port diff --git a/src/lib/PySocks/sockshandler.py b/src/lib/PySocks/sockshandler.py deleted file mode 100644 index 26c83439..00000000 --- a/src/lib/PySocks/sockshandler.py +++ /dev/null @@ -1,79 +0,0 @@ -#!/usr/bin/env python -""" -SocksiPy + urllib2 handler - -version: 0.3 -author: e - -This module provides a Handler which you can use with urllib2 to allow it to tunnel your connection through a socks.sockssocket socket, with out monkey patching the original socket... -""" -import ssl - -try: - import urllib2 - import httplib -except ImportError: # Python 3 - import urllib.request as urllib2 - import http.client as httplib - -import socks # $ pip install PySocks - -def merge_dict(a, b): - d = a.copy() - d.update(b) - return d - -class SocksiPyConnection(httplib.HTTPConnection): - def __init__(self, proxytype, proxyaddr, proxyport=None, rdns=True, username=None, password=None, *args, **kwargs): - self.proxyargs = (proxytype, proxyaddr, proxyport, rdns, username, password) - httplib.HTTPConnection.__init__(self, *args, **kwargs) - - def connect(self): - self.sock = socks.socksocket() - self.sock.setproxy(*self.proxyargs) - if type(self.timeout) in (int, float): - self.sock.settimeout(self.timeout) - self.sock.connect((self.host, self.port)) - -class SocksiPyConnectionS(httplib.HTTPSConnection): - def __init__(self, proxytype, proxyaddr, proxyport=None, rdns=True, username=None, password=None, *args, **kwargs): - self.proxyargs = (proxytype, proxyaddr, proxyport, rdns, username, password) - httplib.HTTPSConnection.__init__(self, *args, **kwargs) - - def connect(self): - sock = socks.socksocket() - sock.setproxy(*self.proxyargs) - if type(self.timeout) in (int, float): - sock.settimeout(self.timeout) - sock.connect((self.host, self.port)) - self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file) - -class SocksiPyHandler(urllib2.HTTPHandler, urllib2.HTTPSHandler): - def __init__(self, *args, **kwargs): - self.args = args - self.kw = kwargs - urllib2.HTTPHandler.__init__(self) - - def http_open(self, req): - def build(host, port=None, timeout=0, **kwargs): - kw = merge_dict(self.kw, kwargs) - conn = SocksiPyConnection(*self.args, host=host, port=port, timeout=timeout, **kw) - return conn - return self.do_open(build, req) - - def https_open(self, req): - def build(host, port=None, timeout=0, **kwargs): - kw = merge_dict(self.kw, kwargs) - conn = SocksiPyConnectionS(*self.args, host=host, port=port, timeout=timeout, **kw) - return conn - return self.do_open(build, req) - -if __name__ == "__main__": - import sys - try: - port = int(sys.argv[1]) - except (ValueError, IndexError): - port = 9050 - opener = urllib2.build_opener(SocksiPyHandler(socks.PROXY_TYPE_SOCKS5, "localhost", port)) - print("HTTP: " + opener.open("http://httpbin.org/ip").read().decode()) - print("HTTPS: " + opener.open("https://httpbin.org/ip").read().decode()) diff --git a/src/lib/bencode/__init__.py b/src/lib/bencode/__init__.py deleted file mode 100644 index c484c651..00000000 --- a/src/lib/bencode/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -try: - string_type = basestring -except NameError: - string_type = str - -from .encode import encode -from .decode import decode diff --git a/src/lib/bencode/decode.py b/src/lib/bencode/decode.py deleted file mode 100644 index 65362490..00000000 --- a/src/lib/bencode/decode.py +++ /dev/null @@ -1,141 +0,0 @@ -import itertools -import collections - -from . import string_type - -try: - range = xrange -except NameError: - pass - -def decode(data): - ''' - Bdecodes data into Python built-in types. - ''' - - return consume(LookaheadIterator(data)) - -class LookaheadIterator(collections.Iterator): - ''' - An iterator that lets you peek at the next item. - ''' - - def __init__(self, iterator): - self.iterator, self.next_iterator = itertools.tee(iter(iterator)) - - # Be one step ahead - self._advance() - - def _advance(self): - self.next_item = next(self.next_iterator, None) - - def __next__(self): - self._advance() - - return next(self.iterator) - - # Python 2 compatibility - next = __next__ - -def consume(stream): - item = stream.next_item - - if item is None: - raise ValueError('Encoding empty data is undefined') - elif item == 'i': - return consume_int(stream) - elif item == 'l': - return consume_list(stream) - elif item == 'd': - return consume_dict(stream) - elif item is not None and item[0].isdigit(): - return consume_str(stream) - else: - raise ValueError('Invalid bencode object type: ', item) - -def consume_number(stream): - result = '' - - while True: - chunk = stream.next_item - - if not chunk.isdigit(): - return result - elif result.startswith('0'): - raise ValueError('Invalid number') - - next(stream) - result += chunk - -def consume_int(stream): - if next(stream) != 'i': - raise ValueError() - - negative = stream.next_item == '-' - - if negative: - next(stream) - - result = int(consume_number(stream)) - - if negative: - result *= -1 - - if result == 0: - raise ValueError('Negative zero is not allowed') - - if next(stream) != 'e': - raise ValueError('Unterminated integer') - - return result - -def consume_str(stream): - length = int(consume_number(stream)) - - if next(stream) != ':': - raise ValueError('Malformed string') - - result = '' - - for i in range(length): - try: - result += next(stream) - except StopIteration: - raise ValueError('Invalid string length') - - return result - -def consume_list(stream): - if next(stream) != 'l': - raise ValueError() - - l = [] - - while stream.next_item != 'e': - l.append(consume(stream)) - - if next(stream) != 'e': - raise ValueError('Unterminated list') - - return l - -def consume_dict(stream): - if next(stream) != 'd': - raise ValueError() - - d = {} - - while stream.next_item != 'e': - key = consume(stream) - - if not isinstance(key, string_type): - raise ValueError('Dictionary keys must be strings') - - value = consume(stream) - - d[key] = value - - if next(stream) != 'e': - raise ValueError('Unterminated dictionary') - - return d diff --git a/src/lib/bencode/encode.py b/src/lib/bencode/encode.py deleted file mode 100644 index be98f994..00000000 --- a/src/lib/bencode/encode.py +++ /dev/null @@ -1,22 +0,0 @@ -from . import string_type - -def encode(obj): - ''' - Bencodes the object. The object must be an instance of: str, int, list, or dict. - ''' - - if isinstance(obj, string_type): - return '{0}:{1}'.format(len(obj), obj) - elif isinstance(obj, int): - return 'i{0}e'.format(obj) - elif isinstance(obj, list): - values = ''.join([encode(o) for o in obj]) - - return 'l{0}e'.format(values) - elif isinstance(obj, dict): - items = sorted(obj.items()) - values = ''.join([encode(str(key)) + encode(value) for key, value in items]) - - return 'd{0}e'.format(values) - else: - raise TypeError('Unsupported type: {0}. Must be one of: str, int, list, dict.'.format(type(obj))) diff --git a/src/lib/geventwebsocket/AUTHORS b/src/lib/geventwebsocket/AUTHORS deleted file mode 100644 index 02de7096..00000000 --- a/src/lib/geventwebsocket/AUTHORS +++ /dev/null @@ -1,9 +0,0 @@ -This Websocket library for Gevent is written and maintained by - - Jeffrey Gelens - - -Contributors: - - Denis Bilenko - Lon Ingram diff --git a/src/lib/geventwebsocket/LICENSE b/src/lib/geventwebsocket/LICENSE deleted file mode 100644 index 2526edb3..00000000 --- a/src/lib/geventwebsocket/LICENSE +++ /dev/null @@ -1,13 +0,0 @@ - Copyright 2011-2017 Jeffrey Gelens - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/src/lib/geventwebsocket/__init__.py b/src/lib/geventwebsocket/__init__.py deleted file mode 100644 index 5ee3f961..00000000 --- a/src/lib/geventwebsocket/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -VERSION = (0, 10, 1, 'final', 0) - -__all__ = [ - 'WebSocketApplication', - 'Resource', - 'WebSocketServer', - 'WebSocketError', - 'get_version' -] - - -def get_version(*args, **kwargs): - from .utils import get_version - return get_version(*args, **kwargs) - -try: - from .resource import WebSocketApplication, Resource - from .server import WebSocketServer - from .exceptions import WebSocketError -except ImportError: - pass diff --git a/src/lib/geventwebsocket/_compat.py b/src/lib/geventwebsocket/_compat.py deleted file mode 100644 index 70354135..00000000 --- a/src/lib/geventwebsocket/_compat.py +++ /dev/null @@ -1,23 +0,0 @@ -from __future__ import absolute_import, division, print_function - -import sys -import codecs - - -PY3 = sys.version_info[0] == 3 -PY2 = sys.version_info[0] == 2 - - -if PY2: - bytes = str - text_type = unicode - string_types = basestring - range_type = xrange - iteritems = lambda x: x.iteritems() - # b = lambda x: x -else: - text_type = str - string_types = str, - range_type = range - iteritems = lambda x: iter(x.items()) - # b = lambda x: codecs.latin_1_encode(x)[0] diff --git a/src/lib/geventwebsocket/exceptions.py b/src/lib/geventwebsocket/exceptions.py deleted file mode 100644 index e066727e..00000000 --- a/src/lib/geventwebsocket/exceptions.py +++ /dev/null @@ -1,19 +0,0 @@ -from socket import error as socket_error - - -class WebSocketError(socket_error): - """ - Base class for all websocket errors. - """ - - -class ProtocolError(WebSocketError): - """ - Raised if an error occurs when de/encoding the websocket protocol. - """ - - -class FrameTooLargeException(ProtocolError): - """ - Raised if a frame is received that is too large. - """ diff --git a/src/lib/geventwebsocket/gunicorn/__init__.py b/src/lib/geventwebsocket/gunicorn/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/lib/geventwebsocket/gunicorn/workers.py b/src/lib/geventwebsocket/gunicorn/workers.py deleted file mode 100644 index d0aa1369..00000000 --- a/src/lib/geventwebsocket/gunicorn/workers.py +++ /dev/null @@ -1,6 +0,0 @@ -from geventwebsocket.handler import WebSocketHandler -from gunicorn.workers.ggevent import GeventPyWSGIWorker - - -class GeventWebSocketWorker(GeventPyWSGIWorker): - wsgi_handler = WebSocketHandler diff --git a/src/lib/geventwebsocket/handler.py b/src/lib/geventwebsocket/handler.py deleted file mode 100644 index 8aec77c0..00000000 --- a/src/lib/geventwebsocket/handler.py +++ /dev/null @@ -1,283 +0,0 @@ -import base64 -import hashlib - -from gevent.pywsgi import WSGIHandler -from ._compat import PY3 -from .websocket import WebSocket, Stream -from .logging import create_logger - - -class Client(object): - def __init__(self, address, ws): - self.address = address - self.ws = ws - - -class WebSocketHandler(WSGIHandler): - """ - Automatically upgrades the connection to a websocket. - - To prevent the WebSocketHandler to call the underlying WSGI application, - but only setup the WebSocket negotiations, do: - - mywebsockethandler.prevent_wsgi_call = True - - before calling run_application(). This is useful if you want to do more - things before calling the app, and want to off-load the WebSocket - negotiations to this library. Socket.IO needs this for example, to send - the 'ack' before yielding the control to your WSGI app. - """ - - SUPPORTED_VERSIONS = ('13', '8', '7') - GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" - - def run_websocket(self): - """ - Called when a websocket has been created successfully. - """ - - if getattr(self, 'prevent_wsgi_call', False): - return - - # In case WebSocketServer is not used - if not hasattr(self.server, 'clients'): - self.server.clients = {} - - # Since we're now a websocket connection, we don't care what the - # application actually responds with for the http response - - try: - self.server.clients[self.client_address] = Client( - self.client_address, self.websocket) - list(self.application(self.environ, lambda s, h, e=None: [])) - finally: - del self.server.clients[self.client_address] - if not self.websocket.closed: - self.websocket.close() - self.environ.update({ - 'wsgi.websocket': None - }) - self.websocket = None - - def run_application(self): - if (hasattr(self.server, 'pre_start_hook') and self.server.pre_start_hook): - self.logger.debug("Calling pre-start hook") - if self.server.pre_start_hook(self): - return super(WebSocketHandler, self).run_application() - - self.logger.debug("Initializing WebSocket") - self.result = self.upgrade_websocket() - - if hasattr(self, 'websocket'): - if self.status and not self.headers_sent: - self.write('') - - self.run_websocket() - else: - if self.status: - # A status was set, likely an error so just send the response - if not self.result: - self.result = [] - - self.process_result() - return - - # This handler did not handle the request, so defer it to the - # underlying application object - return super(WebSocketHandler, self).run_application() - - def upgrade_websocket(self): - """ - Attempt to upgrade the current environ into a websocket enabled - connection. If successful, the environ dict with be updated with two - new entries, `wsgi.websocket` and `wsgi.websocket_version`. - - :returns: Whether the upgrade was successful. - """ - - # Some basic sanity checks first - - self.logger.debug("Validating WebSocket request") - - if self.environ.get('REQUEST_METHOD', '') != 'GET': - # This is not a websocket request, so we must not handle it - self.logger.debug('Can only upgrade connection if using GET method.') - return - - upgrade = self.environ.get('HTTP_UPGRADE', '').lower() - - if upgrade == 'websocket': - connection = self.environ.get('HTTP_CONNECTION', '').lower() - - if 'upgrade' not in connection: - # This is not a websocket request, so we must not handle it - self.logger.warning("Client didn't ask for a connection " - "upgrade") - return - else: - # This is not a websocket request, so we must not handle it - return - - if self.request_version != 'HTTP/1.1': - self.start_response('402 Bad Request', []) - self.logger.warning("Bad server protocol in headers") - - return ['Bad protocol version'] - - if self.environ.get('HTTP_SEC_WEBSOCKET_VERSION'): - return self.upgrade_connection() - else: - self.logger.warning("No protocol defined") - self.start_response('426 Upgrade Required', [ - ('Sec-WebSocket-Version', ', '.join(self.SUPPORTED_VERSIONS))]) - - return ['No Websocket protocol version defined'] - - def upgrade_connection(self): - """ - Validate and 'upgrade' the HTTP request to a WebSocket request. - - If an upgrade succeeded then then handler will have `start_response` - with a status of `101`, the environ will also be updated with - `wsgi.websocket` and `wsgi.websocket_version` keys. - - :param environ: The WSGI environ dict. - :param start_response: The callable used to start the response. - :param stream: File like object that will be read from/written to by - the underlying WebSocket object, if created. - :return: The WSGI response iterator is something went awry. - """ - - self.logger.debug("Attempting to upgrade connection") - - version = self.environ.get("HTTP_SEC_WEBSOCKET_VERSION") - - if version not in self.SUPPORTED_VERSIONS: - msg = "Unsupported WebSocket Version: {0}".format(version) - - self.logger.warning(msg) - self.start_response('400 Bad Request', [ - ('Sec-WebSocket-Version', ', '.join(self.SUPPORTED_VERSIONS)) - ]) - - return [msg] - - key = self.environ.get("HTTP_SEC_WEBSOCKET_KEY", '').strip() - - if not key: - # 5.2.1 (3) - msg = "Sec-WebSocket-Key header is missing/empty" - - self.logger.warning(msg) - self.start_response('400 Bad Request', []) - - return [msg] - - try: - key_len = len(base64.b64decode(key)) - except TypeError: - msg = "Invalid key: {0}".format(key) - - self.logger.warning(msg) - self.start_response('400 Bad Request', []) - - return [msg] - - if key_len != 16: - # 5.2.1 (3) - msg = "Invalid key: {0}".format(key) - - self.logger.warning(msg) - self.start_response('400 Bad Request', []) - - return [msg] - - # Check for WebSocket Protocols - requested_protocols = self.environ.get( - 'HTTP_SEC_WEBSOCKET_PROTOCOL', '') - protocol = None - - if hasattr(self.application, 'app_protocol'): - allowed_protocol = self.application.app_protocol( - self.environ['PATH_INFO']) - - if allowed_protocol and allowed_protocol in requested_protocols: - protocol = allowed_protocol - self.logger.debug("Protocol allowed: {0}".format(protocol)) - - self.websocket = WebSocket(self.environ, Stream(self), self) - self.environ.update({ - 'wsgi.websocket_version': version, - 'wsgi.websocket': self.websocket - }) - - if PY3: - accept = base64.b64encode( - hashlib.sha1((key + self.GUID).encode("latin-1")).digest() - ).decode("latin-1") - else: - accept = base64.b64encode(hashlib.sha1(key + self.GUID).digest()) - - headers = [ - ("Upgrade", "websocket"), - ("Connection", "Upgrade"), - ("Sec-WebSocket-Accept", accept) - ] - - if protocol: - headers.append(("Sec-WebSocket-Protocol", protocol)) - - self.logger.debug("WebSocket request accepted, switching protocols") - self.start_response("101 Switching Protocols", headers) - - @property - def logger(self): - if not hasattr(self.server, 'logger'): - self.server.logger = create_logger(__name__) - - return self.server.logger - - def log_request(self): - if '101' not in str(self.status): - self.logger.info(self.format_request()) - - @property - def active_client(self): - return self.server.clients[self.client_address] - - def start_response(self, status, headers, exc_info=None): - """ - Called when the handler is ready to send a response back to the remote - endpoint. A websocket connection may have not been created. - """ - writer = super(WebSocketHandler, self).start_response( - status, headers, exc_info=exc_info) - - self._prepare_response() - - return writer - - def _prepare_response(self): - """ - Sets up the ``pywsgi.Handler`` to work with a websocket response. - - This is used by other projects that need to support WebSocket - connections as part of a larger effort. - """ - assert not self.headers_sent - - if not self.environ.get('wsgi.websocket'): - # a WebSocket connection is not established, do nothing - return - - # So that `finalize_headers` doesn't write a Content-Length header - self.provided_content_length = False - - # The websocket is now controlling the response - self.response_use_chunked = False - - # Once the request is over, the connection must be closed - self.close_connection = True - - # Prevents the Date header from being written - self.provided_date = True diff --git a/src/lib/geventwebsocket/logging.py b/src/lib/geventwebsocket/logging.py deleted file mode 100644 index ac0c9692..00000000 --- a/src/lib/geventwebsocket/logging.py +++ /dev/null @@ -1,32 +0,0 @@ -from __future__ import absolute_import - -from logging import getLogger, StreamHandler, getLoggerClass, Formatter, DEBUG, INFO - - -def create_logger(name, debug=False, format=None): - Logger = getLoggerClass() - - class DebugLogger(Logger): - def getEffectiveLevel(x): - if x.level == 0 and debug: - return DEBUG - else: - return Logger.getEffectiveLevel(x) - - class DebugHandler(StreamHandler): - def emit(x, record): - StreamHandler.emit(x, record) if debug else None - - handler = DebugHandler() - handler.setLevel(DEBUG) - - if format: - handler.setFormatter(Formatter(format)) - - logger = getLogger(name) - del logger.handlers[:] - logger.__class__ = DebugLogger - logger.addHandler(handler) - logger.setLevel(INFO) - - return logger diff --git a/src/lib/geventwebsocket/protocols/__init__.py b/src/lib/geventwebsocket/protocols/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/lib/geventwebsocket/protocols/base.py b/src/lib/geventwebsocket/protocols/base.py deleted file mode 100644 index 1c05ab62..00000000 --- a/src/lib/geventwebsocket/protocols/base.py +++ /dev/null @@ -1,35 +0,0 @@ -class BaseProtocol(object): - PROTOCOL_NAME = '' - - def __init__(self, app): - self._app = app - - def on_open(self): - self.app.on_open() - - def on_message(self, message): - self.app.on_message(message) - - def on_close(self, reason=None): - self.app.on_close(reason) - - @property - def app(self): - if self._app: - return self._app - else: - raise Exception("No application coupled") - - @property - def server(self): - if not hasattr(self.app, 'ws'): - return None - - return self.app.ws.handler.server - - @property - def handler(self): - if not hasattr(self.app, 'ws'): - return None - - return self.app.ws.handler diff --git a/src/lib/geventwebsocket/protocols/wamp.py b/src/lib/geventwebsocket/protocols/wamp.py deleted file mode 100644 index c89775be..00000000 --- a/src/lib/geventwebsocket/protocols/wamp.py +++ /dev/null @@ -1,235 +0,0 @@ -import inspect -import random -import string -import types - -try: - import ujson as json -except ImportError: - try: - import simplejson as json - except ImportError: - import json - -from .._compat import range_type, string_types -from ..exceptions import WebSocketError -from .base import BaseProtocol - - -def export_rpc(arg=None): - if isinstance(arg, types.FunctionType): - arg._rpc = arg.__name__ - return arg - - -def serialize(data): - return json.dumps(data) - - -class Prefixes(object): - def __init__(self): - self.prefixes = {} - - def add(self, prefix, uri): - self.prefixes[prefix] = uri - - def resolve(self, curie_or_uri): - if "http://" in curie_or_uri: - return curie_or_uri - elif ':' in curie_or_uri: - prefix, proc = curie_or_uri.split(':', 1) - return self.prefixes[prefix] + proc - else: - raise Exception(curie_or_uri) - - -class RemoteProcedures(object): - def __init__(self): - self.calls = {} - - def register_procedure(self, uri, proc): - self.calls[uri] = proc - - def register_object(self, uri, obj): - for k in inspect.getmembers(obj, inspect.ismethod): - if '_rpc' in k[1].__dict__: - proc_uri = uri + k[1]._rpc - self.calls[proc_uri] = (obj, k[1]) - - def call(self, uri, args): - if uri in self.calls: - proc = self.calls[uri] - - # Do the correct call whether it's a function or instance method. - if isinstance(proc, tuple): - if proc[1].__self__ is None: - # Create instance of object and call method - return proc[1](proc[0](), *args) - else: - # Call bound method on instance - return proc[1](*args) - else: - return self.calls[uri](*args) - else: - raise Exception("no such uri '{}'".format(uri)) - - -class Channels(object): - def __init__(self): - self.channels = {} - - def create(self, uri, prefix_matching=False): - if uri not in self.channels: - self.channels[uri] = [] - - # TODO: implement prefix matching - - def subscribe(self, uri, client): - if uri in self.channels: - self.channels[uri].append(client) - - def unsubscribe(self, uri, client): - if uri not in self.channels: - return - - client_index = self.channels[uri].index(client) - self.channels[uri].pop(client_index) - - if len(self.channels[uri]) == 0: - del self.channels[uri] - - def publish(self, uri, event, exclude=None, eligible=None): - if uri not in self.channels: - return - - # TODO: exclude & eligible - - msg = [WampProtocol.MSG_EVENT, uri, event] - - for client in self.channels[uri]: - try: - client.ws.send(serialize(msg)) - except WebSocketError: - # Seems someone didn't unsubscribe before disconnecting - self.channels[uri].remove(client) - - -class WampProtocol(BaseProtocol): - MSG_WELCOME = 0 - MSG_PREFIX = 1 - MSG_CALL = 2 - MSG_CALL_RESULT = 3 - MSG_CALL_ERROR = 4 - MSG_SUBSCRIBE = 5 - MSG_UNSUBSCRIBE = 6 - MSG_PUBLISH = 7 - MSG_EVENT = 8 - - PROTOCOL_NAME = "wamp" - - def __init__(self, *args, **kwargs): - self.procedures = RemoteProcedures() - self.prefixes = Prefixes() - self.session_id = ''.join( - [random.choice(string.digits + string.letters) - for i in range_type(16)]) - - super(WampProtocol, self).__init__(*args, **kwargs) - - def register_procedure(self, *args, **kwargs): - self.procedures.register_procedure(*args, **kwargs) - - def register_object(self, *args, **kwargs): - self.procedures.register_object(*args, **kwargs) - - def register_pubsub(self, *args, **kwargs): - if not hasattr(self.server, 'channels'): - self.server.channels = Channels() - - self.server.channels.create(*args, **kwargs) - - def do_handshake(self): - from geventwebsocket import get_version - - welcome = [ - self.MSG_WELCOME, - self.session_id, - 1, - 'gevent-websocket/' + get_version() - ] - self.app.ws.send(serialize(welcome)) - - def _get_exception_info(self, e): - uri = 'http://TODO#generic' - desc = str(type(e)) - details = str(e) - return [uri, desc, details] - - def rpc_call(self, data): - call_id, curie_or_uri = data[1:3] - args = data[3:] - - if not isinstance(call_id, string_types): - raise Exception() - if not isinstance(curie_or_uri, string_types): - raise Exception() - - uri = self.prefixes.resolve(curie_or_uri) - - try: - result = self.procedures.call(uri, args) - result_msg = [self.MSG_CALL_RESULT, call_id, result] - except Exception as e: - result_msg = [self.MSG_CALL_ERROR, - call_id] + self._get_exception_info(e) - - self.app.on_message(serialize(result_msg)) - - def pubsub_action(self, data): - action = data[0] - curie_or_uri = data[1] - - if not isinstance(action, int): - raise Exception() - if not isinstance(curie_or_uri, string_types): - raise Exception() - - uri = self.prefixes.resolve(curie_or_uri) - - if action == self.MSG_SUBSCRIBE and len(data) == 2: - self.server.channels.subscribe(data[1], self.handler.active_client) - - elif action == self.MSG_UNSUBSCRIBE and len(data) == 2: - self.server.channels.unsubscribe( - data[1], self.handler.active_client) - - elif action == self.MSG_PUBLISH and len(data) >= 3: - payload = data[2] if len(data) >= 3 else None - exclude = data[3] if len(data) >= 4 else None - eligible = data[4] if len(data) >= 5 else None - - self.server.channels.publish(uri, payload, exclude, eligible) - - def on_open(self): - self.app.on_open() - self.do_handshake() - - def on_message(self, message): - data = json.loads(message) - - if not isinstance(data, list): - raise Exception('incoming data is no list') - - if data[0] == self.MSG_PREFIX and len(data) == 3: - prefix, uri = data[1:3] - self.prefixes.add(prefix, uri) - - elif data[0] == self.MSG_CALL and len(data) >= 3: - return self.rpc_call(data) - - elif data[0] in (self.MSG_SUBSCRIBE, self.MSG_UNSUBSCRIBE, - self.MSG_PUBLISH): - return self.pubsub_action(data) - else: - raise Exception("Unknown call") - diff --git a/src/lib/geventwebsocket/resource.py b/src/lib/geventwebsocket/resource.py deleted file mode 100644 index 549f0d32..00000000 --- a/src/lib/geventwebsocket/resource.py +++ /dev/null @@ -1,100 +0,0 @@ -import re -import warnings - -from .protocols.base import BaseProtocol -from .exceptions import WebSocketError - -try: - from collections import OrderedDict -except ImportError: - class OrderedDict: - pass - - -class WebSocketApplication(object): - protocol_class = BaseProtocol - - def __init__(self, ws): - self.protocol = self.protocol_class(self) - self.ws = ws - - def handle(self): - self.protocol.on_open() - - while True: - try: - message = self.ws.receive() - except WebSocketError: - self.protocol.on_close() - break - - self.protocol.on_message(message) - - def on_open(self, *args, **kwargs): - pass - - def on_close(self, *args, **kwargs): - pass - - def on_message(self, message, *args, **kwargs): - self.ws.send(message, **kwargs) - - @classmethod - def protocol_name(cls): - return cls.protocol_class.PROTOCOL_NAME - - -class Resource(object): - def __init__(self, apps=None): - self.apps = apps if apps else [] - - if isinstance(apps, dict): - if not isinstance(apps, OrderedDict): - warnings.warn("Using an unordered dictionary for the " - "app list is discouraged and may lead to " - "undefined behavior.", UserWarning) - - self.apps = apps.items() - - # An app can either be a standard WSGI application (an object we call with - # __call__(self, environ, start_response)) or a class we instantiate - # (and which can handle websockets). This function tells them apart. - # Override this if you have apps that can handle websockets but don't - # fulfill these criteria. - def _is_websocket_app(self, app): - return isinstance(app, type) and issubclass(app, WebSocketApplication) - - def _app_by_path(self, environ_path, is_websocket_request): - # Which app matched the current path? - for path, app in self.apps: - if re.match(path, environ_path): - if is_websocket_request == self._is_websocket_app(app): - return app - return None - - def app_protocol(self, path): - # app_protocol will only be called for websocket apps - app = self._app_by_path(path, True) - - if hasattr(app, 'protocol_name'): - return app.protocol_name() - else: - return '' - - def __call__(self, environ, start_response): - environ = environ - is_websocket_call = 'wsgi.websocket' in environ - current_app = self._app_by_path(environ['PATH_INFO'], is_websocket_call) - - if current_app is None: - raise Exception("No apps defined") - - if is_websocket_call: - ws = environ['wsgi.websocket'] - current_app = current_app(ws) - current_app.ws = ws # TODO: needed? - current_app.handle() - # Always return something, calling WSGI middleware may rely on it - return [] - else: - return current_app(environ, start_response) diff --git a/src/lib/geventwebsocket/server.py b/src/lib/geventwebsocket/server.py deleted file mode 100644 index e939bd11..00000000 --- a/src/lib/geventwebsocket/server.py +++ /dev/null @@ -1,34 +0,0 @@ -from gevent.pywsgi import WSGIServer - -from .handler import WebSocketHandler -from .logging import create_logger - - -class WebSocketServer(WSGIServer): - handler_class = WebSocketHandler - debug_log_format = ( - '-' * 80 + '\n' + - '%(levelname)s in %(module)s [%(pathname)s:%(lineno)d]:\n' + - '%(message)s\n' + - '-' * 80 - ) - - def __init__(self, *args, **kwargs): - self.debug = kwargs.pop('debug', False) - self.pre_start_hook = kwargs.pop('pre_start_hook', None) - self._logger = None - self.clients = {} - - super(WebSocketServer, self).__init__(*args, **kwargs) - - def handle(self, socket, address): - handler = self.handler_class(socket, address, self) - handler.handle() - - @property - def logger(self): - if not self._logger: - self._logger = create_logger( - __name__, self.debug, self.debug_log_format) - - return self._logger diff --git a/src/lib/geventwebsocket/utf8validator.py b/src/lib/geventwebsocket/utf8validator.py deleted file mode 100644 index d604f966..00000000 --- a/src/lib/geventwebsocket/utf8validator.py +++ /dev/null @@ -1,224 +0,0 @@ -from ._compat import PY3 - -############################################################################### -# -# The MIT License (MIT) -# -# Copyright (c) Crossbar.io Technologies GmbH -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -# -############################################################################### - -# Note: This code is a Python implementation of the algorithm -# "Flexible and Economical UTF-8 Decoder" by Bjoern Hoehrmann -# bjoern@hoehrmann.de, http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ - -__all__ = ("Utf8Validator",) - - -# DFA transitions -UTF8VALIDATOR_DFA = ( - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, # 00..1f - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, # 20..3f - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, # 40..5f - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, # 60..7f - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, # 80..9f - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, # a0..bf - 8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, # c0..df - 0xa, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, # e0..ef - 0xb, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, # f0..ff - 0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, # s0..s0 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, # s1..s2 - 1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, # s3..s4 - 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, # s5..s6 - 1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, # s7..s8 -) - -UTF8_ACCEPT = 0 -UTF8_REJECT = 1 - - -# use Cython implementation of UTF8 validator if available -# -try: - from wsaccel.utf8validator import Utf8Validator - -except ImportError: - # - # Fallback to pure Python implementation - also for PyPy. - # - # Do NOT touch this code unless you know what you are doing! - # https://github.com/oberstet/scratchbox/tree/master/python/utf8 - # - - if PY3: - - # Python 3 and above - - # convert DFA table to bytes (performance) - UTF8VALIDATOR_DFA_S = bytes(UTF8VALIDATOR_DFA) - - class Utf8Validator(object): - """ - Incremental UTF-8 validator with constant memory consumption (minimal state). - - Implements the algorithm "Flexible and Economical UTF-8 Decoder" by - Bjoern Hoehrmann (http://bjoern.hoehrmann.de/utf-8/decoder/dfa/). - """ - - def __init__(self): - self.reset() - - def decode(self, b): - """ - Eat one UTF-8 octet, and validate on the fly. - - Returns ``UTF8_ACCEPT`` when enough octets have been consumed, in which case - ``self.codepoint`` contains the decoded Unicode code point. - - Returns ``UTF8_REJECT`` when invalid UTF-8 was encountered. - - Returns some other positive integer when more octets need to be eaten. - """ - tt = UTF8VALIDATOR_DFA_S[b] - if self.state != UTF8_ACCEPT: - self.codepoint = (b & 0x3f) | (self.codepoint << 6) - else: - self.codepoint = (0xff >> tt) & b - self.state = UTF8VALIDATOR_DFA_S[256 + self.state * 16 + tt] - return self.state - - def reset(self): - """ - Reset validator to start new incremental UTF-8 decode/validation. - """ - self.state = UTF8_ACCEPT # the empty string is valid UTF8 - self.codepoint = 0 - self.i = 0 - - def validate(self, ba): - """ - Incrementally validate a chunk of bytes provided as string. - - Will return a quad ``(valid?, endsOnCodePoint?, currentIndex, totalIndex)``. - - As soon as an octet is encountered which renders the octet sequence - invalid, a quad with ``valid? == False`` is returned. ``currentIndex`` returns - the index within the currently consumed chunk, and ``totalIndex`` the - index within the total consumed sequence that was the point of bail out. - When ``valid? == True``, currentIndex will be ``len(ba)`` and ``totalIndex`` the - total amount of consumed bytes. - """ - # - # The code here is written for optimal JITting in PyPy, not for best - # readability by your grandma or particular elegance. Do NOT touch! - # - l = len(ba) - i = 0 - state = self.state - while i < l: - # optimized version of decode(), since we are not interested in actual code points - state = UTF8VALIDATOR_DFA_S[256 + (state << 4) + UTF8VALIDATOR_DFA_S[ba[i]]] - if state == UTF8_REJECT: - self.state = state - self.i += i - return False, False, i, self.i - i += 1 - self.state = state - self.i += l - return True, state == UTF8_ACCEPT, l, self.i - - else: - - # convert DFA table to string (performance) - UTF8VALIDATOR_DFA_S = ''.join([chr(c) for c in UTF8VALIDATOR_DFA]) - - class Utf8Validator(object): - """ - Incremental UTF-8 validator with constant memory consumption (minimal state). - - Implements the algorithm "Flexible and Economical UTF-8 Decoder" by - Bjoern Hoehrmann (http://bjoern.hoehrmann.de/utf-8/decoder/dfa/). - """ - - def __init__(self): - self.reset() - - def decode(self, b): - """ - Eat one UTF-8 octet, and validate on the fly. - - Returns ``UTF8_ACCEPT`` when enough octets have been consumed, in which case - ``self.codepoint`` contains the decoded Unicode code point. - - Returns ``UTF8_REJECT`` when invalid UTF-8 was encountered. - - Returns some other positive integer when more octets need to be eaten. - """ - tt = ord(UTF8VALIDATOR_DFA_S[b]) - if self.state != UTF8_ACCEPT: - self.codepoint = (b & 0x3f) | (self.codepoint << 6) - else: - self.codepoint = (0xff >> tt) & b - self.state = ord(UTF8VALIDATOR_DFA_S[256 + self.state * 16 + tt]) - return self.state - - def reset(self): - """ - Reset validator to start new incremental UTF-8 decode/validation. - """ - self.state = UTF8_ACCEPT # the empty string is valid UTF8 - self.codepoint = 0 - self.i = 0 - - def validate(self, ba): - """ - Incrementally validate a chunk of bytes provided as string. - - Will return a quad ``(valid?, endsOnCodePoint?, currentIndex, totalIndex)``. - - As soon as an octet is encountered which renders the octet sequence - invalid, a quad with ``valid? == False`` is returned. ``currentIndex`` returns - the index within the currently consumed chunk, and ``totalIndex`` the - index within the total consumed sequence that was the point of bail out. - When ``valid? == True``, currentIndex will be ``len(ba)`` and ``totalIndex`` the - total amount of consumed bytes. - """ - # - # The code here is written for optimal JITting in PyPy, not for best - # readability by your grandma or particular elegance. Do NOT touch! - # - l = len(ba) - i = 0 - state = self.state - while i < l: - # optimized version of decode(), since we are not interested in actual code points - try: - state = ord(UTF8VALIDATOR_DFA_S[256 + (state << 4) + ord(UTF8VALIDATOR_DFA_S[ba[i]])]) - except: - import ipdb; ipdb.set_trace() - if state == UTF8_REJECT: - self.state = state - self.i += i - return False, False, i, self.i - i += 1 - self.state = state - self.i += l - return True, state == UTF8_ACCEPT, l, self.i diff --git a/src/lib/geventwebsocket/utils.py b/src/lib/geventwebsocket/utils.py deleted file mode 100644 index 2e5bc3b7..00000000 --- a/src/lib/geventwebsocket/utils.py +++ /dev/null @@ -1,45 +0,0 @@ -import subprocess - - -def get_version(version=None): - "Returns a PEP 386-compliant version number from VERSION." - - if version is None: - from geventwebsocket import VERSION as version - else: - assert len(version) == 5 - assert version[3] in ('alpha', 'beta', 'rc', 'final') - - # Now build the two parts of the version number: - # main = X.Y[.Z] - # sub = .devN - for pre-alpha releases - # | {a|b|c}N - for alpha, beta and rc releases - - parts = 2 if version[2] == 0 else 3 - main = '.'.join(str(x) for x in version[:parts]) - - sub = '' - if version[3] == 'alpha' and version[4] == 0: - hg_changeset = get_hg_changeset() - if hg_changeset: - sub = '.dev{0}'.format(hg_changeset) - - elif version[3] != 'final': - mapping = {'alpha': 'a', 'beta': 'b', 'rc': 'c'} - sub = mapping[version[3]] + str(version[4]) - - return str(main + sub) - - -def get_hg_changeset(): - rev, err = subprocess.Popen( - 'hg id -i', - shell=True, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE - ).communicate() - - if err: - return None - else: - return rev.strip().replace('+', '') diff --git a/src/lib/geventwebsocket/websocket.py b/src/lib/geventwebsocket/websocket.py deleted file mode 100644 index 7aad7698..00000000 --- a/src/lib/geventwebsocket/websocket.py +++ /dev/null @@ -1,570 +0,0 @@ -import struct -import socket - -from ._compat import string_types, range_type, text_type -from .exceptions import ProtocolError -from .exceptions import WebSocketError -from .exceptions import FrameTooLargeException -from .utf8validator import Utf8Validator - - -MSG_SOCKET_DEAD = "Socket is dead" -MSG_ALREADY_CLOSED = "Connection is already closed" -MSG_CLOSED = "Connection closed" - - -class WebSocket(object): - """ - Base class for supporting websocket operations. - - :ivar environ: The http environment referenced by this connection. - :ivar closed: Whether this connection is closed/closing. - :ivar stream: The underlying file like object that will be read from / - written to by this WebSocket object. - """ - - __slots__ = ('utf8validator', 'utf8validate_last', 'environ', 'closed', - 'stream', 'raw_write', 'raw_read', 'handler') - - OPCODE_CONTINUATION = 0x00 - OPCODE_TEXT = 0x01 - OPCODE_BINARY = 0x02 - OPCODE_CLOSE = 0x08 - OPCODE_PING = 0x09 - OPCODE_PONG = 0x0a - - def __init__(self, environ, stream, handler): - self.environ = environ - self.closed = False - - self.stream = stream - - self.raw_write = stream.write - self.raw_read = stream.read - - self.utf8validator = Utf8Validator() - self.handler = handler - - def __del__(self): - try: - self.close() - except: - # close() may fail if __init__ didn't complete - pass - - def _decode_bytes(self, bytestring): - """ - Internal method used to convert the utf-8 encoded bytestring into - unicode. - - If the conversion fails, the socket will be closed. - """ - - if not bytestring: - return '' - - try: - return bytestring.decode('utf-8') - except UnicodeDecodeError: - self.close(1007) - - raise - - def _encode_bytes(self, text): - """ - :returns: The utf-8 byte string equivalent of `text`. - """ - - if not isinstance(text, str): - text = text_type(text or '') - - return text.encode("utf-8") - - def _is_valid_close_code(self, code): - """ - :returns: Whether the returned close code is a valid hybi return code. - """ - if code < 1000: - return False - - if 1004 <= code <= 1006: - return False - - if 1012 <= code <= 1016: - return False - - if code == 1100: - # not sure about this one but the autobahn fuzzer requires it. - return False - - if 2000 <= code <= 2999: - return False - - return True - - @property - def current_app(self): - if hasattr(self.handler.server.application, 'current_app'): - return self.handler.server.application.current_app - else: - # For backwards compatibility reasons - class MockApp(): - def on_close(self, *args): - pass - - return MockApp() - - @property - def origin(self): - if not self.environ: - return - - return self.environ.get('HTTP_ORIGIN') - - @property - def protocol(self): - if not self.environ: - return - - return self.environ.get('HTTP_SEC_WEBSOCKET_PROTOCOL') - - @property - def version(self): - if not self.environ: - return - - return self.environ.get('HTTP_SEC_WEBSOCKET_VERSION') - - @property - def path(self): - if not self.environ: - return - - return self.environ.get('PATH_INFO') - - @property - def logger(self): - return self.handler.logger - - def handle_close(self, header, payload): - """ - Called when a close frame has been decoded from the stream. - - :param header: The decoded `Header`. - :param payload: The bytestring payload associated with the close frame. - """ - if not payload: - self.close(1000, None) - - return - - if len(payload) < 2: - raise ProtocolError('Invalid close frame: {0} {1}'.format( - header, payload)) - - code = struct.unpack('!H', payload[:2])[0] - payload = payload[2:] - - if payload: - validator = Utf8Validator() - val = validator.validate(payload) - - if not val[0]: - raise UnicodeError - - if not self._is_valid_close_code(code): - raise ProtocolError('Invalid close code {0}'.format(code)) - - self.close(code, payload) - - def handle_ping(self, header, payload): - self.send_frame(payload, self.OPCODE_PONG) - - def handle_pong(self, header, payload): - pass - - def read_frame(self): - """ - Block until a full frame has been read from the socket. - - This is an internal method as calling this will not cleanup correctly - if an exception is called. Use `receive` instead. - - :return: The header and payload as a tuple. - """ - - header = Header.decode_header(self.stream) - - if header.flags: - raise ProtocolError - - if not header.length: - return header, b'' - - try: - payload = self.raw_read(header.length) - except socket.error: - payload = b'' - except Exception: - # TODO log out this exception - payload = b'' - - if len(payload) != header.length: - raise WebSocketError('Unexpected EOF reading frame payload') - - if header.mask: - payload = header.unmask_payload(payload) - - return header, payload - - def validate_utf8(self, payload): - # Make sure the frames are decodable independently - self.utf8validate_last = self.utf8validator.validate(payload) - - if not self.utf8validate_last[0]: - raise UnicodeError("Encountered invalid UTF-8 while processing " - "text message at payload octet index " - "{0:d}".format(self.utf8validate_last[3])) - - def read_message(self): - """ - Return the next text or binary message from the socket. - - This is an internal method as calling this will not cleanup correctly - if an exception is called. Use `receive` instead. - """ - opcode = None - message = bytearray() - - while True: - header, payload = self.read_frame() - f_opcode = header.opcode - - if f_opcode in (self.OPCODE_TEXT, self.OPCODE_BINARY): - # a new frame - if opcode: - raise ProtocolError("The opcode in non-fin frame is " - "expected to be zero, got " - "{0!r}".format(f_opcode)) - - # Start reading a new message, reset the validator - self.utf8validator.reset() - self.utf8validate_last = (True, True, 0, 0) - - opcode = f_opcode - - elif f_opcode == self.OPCODE_CONTINUATION: - if not opcode: - raise ProtocolError("Unexpected frame with opcode=0") - - elif f_opcode == self.OPCODE_PING: - self.handle_ping(header, payload) - continue - - elif f_opcode == self.OPCODE_PONG: - self.handle_pong(header, payload) - continue - - elif f_opcode == self.OPCODE_CLOSE: - self.handle_close(header, payload) - return - - else: - raise ProtocolError("Unexpected opcode={0!r}".format(f_opcode)) - - if opcode == self.OPCODE_TEXT: - self.validate_utf8(payload) - - message += payload - - if header.fin: - break - - if opcode == self.OPCODE_TEXT: - self.validate_utf8(message) - return self._decode_bytes(message) - else: - return message - - def receive(self): - """ - Read and return a message from the stream. If `None` is returned, then - the socket is considered closed/errored. - """ - - if self.closed: - self.current_app.on_close(MSG_ALREADY_CLOSED) - raise WebSocketError(MSG_ALREADY_CLOSED) - - try: - return self.read_message() - except UnicodeError: - self.close(1007) - except ProtocolError: - self.close(1002) - except socket.timeout: - self.close() - self.current_app.on_close(MSG_CLOSED) - except socket.error: - self.close() - self.current_app.on_close(MSG_CLOSED) - - return None - - def send_frame(self, message, opcode): - """ - Send a frame over the websocket with message as its payload - """ - if self.closed: - self.current_app.on_close(MSG_ALREADY_CLOSED) - raise WebSocketError(MSG_ALREADY_CLOSED) - - if not message: - return - - if opcode in (self.OPCODE_TEXT, self.OPCODE_PING): - message = self._encode_bytes(message) - elif opcode == self.OPCODE_BINARY: - message = bytes(message) - - header = Header.encode_header(True, opcode, b'', len(message), 0) - - try: - self.raw_write(header + message) - except socket.error: - raise WebSocketError(MSG_SOCKET_DEAD) - except: - raise - - def send(self, message, binary=None): - """ - Send a frame over the websocket with message as its payload - """ - if binary is None: - binary = not isinstance(message, string_types) - - opcode = self.OPCODE_BINARY if binary else self.OPCODE_TEXT - - try: - self.send_frame(message, opcode) - except WebSocketError: - self.current_app.on_close(MSG_SOCKET_DEAD) - raise WebSocketError(MSG_SOCKET_DEAD) - - def close(self, code=1000, message=b''): - """ - Close the websocket and connection, sending the specified code and - message. The underlying socket object is _not_ closed, that is the - responsibility of the initiator. - """ - - if self.closed: - self.current_app.on_close(MSG_ALREADY_CLOSED) - - try: - message = self._encode_bytes(message) - - self.send_frame(message, opcode=self.OPCODE_CLOSE) - except WebSocketError: - # Failed to write the closing frame but it's ok because we're - # closing the socket anyway. - self.logger.debug("Failed to write closing frame -> closing socket") - finally: - self.logger.debug("Closed WebSocket") - self.closed = True - - self.stream = None - self.raw_write = None - self.raw_read = None - - self.environ = None - - #self.current_app.on_close(MSG_ALREADY_CLOSED) - - -class Stream(object): - """ - Wraps the handler's socket/rfile attributes and makes it in to a file like - object that can be read from/written to by the lower level websocket api. - """ - - __slots__ = ('handler', 'read', 'write') - - def __init__(self, handler): - self.handler = handler - self.read = handler.rfile.read - self.write = handler.socket.sendall - - -class Header(object): - __slots__ = ('fin', 'mask', 'opcode', 'flags', 'length') - - FIN_MASK = 0x80 - OPCODE_MASK = 0x0f - MASK_MASK = 0x80 - LENGTH_MASK = 0x7f - - RSV0_MASK = 0x40 - RSV1_MASK = 0x20 - RSV2_MASK = 0x10 - - # bitwise mask that will determine the reserved bits for a frame header - HEADER_FLAG_MASK = RSV0_MASK | RSV1_MASK | RSV2_MASK - - def __init__(self, fin=0, opcode=0, flags=0, length=0): - self.mask = '' - self.fin = fin - self.opcode = opcode - self.flags = flags - self.length = length - - def mask_payload(self, payload): - payload = bytearray(payload) - mask = bytearray(self.mask) - - for i in range_type(self.length): - payload[i] ^= mask[i % 4] - - return payload - - # it's the same operation - unmask_payload = mask_payload - - def __repr__(self): - opcodes = { - 0: 'continuation(0)', - 1: 'text(1)', - 2: 'binary(2)', - 8: 'close(8)', - 9: 'ping(9)', - 10: 'pong(10)' - } - flags = { - 0x40: 'RSV1 MASK', - 0x20: 'RSV2 MASK', - 0x10: 'RSV3 MASK' - } - - return ("
").format( - self.fin, - opcodes.get(self.opcode, 'reserved({})'.format(self.opcode)), - self.length, - flags.get(self.flags, 'reserved({})'.format(self.flags)), - self.mask, id(self) - ) - - @classmethod - def decode_header(cls, stream): - """ - Decode a WebSocket header. - - :param stream: A file like object that can be 'read' from. - :returns: A `Header` instance. - """ - read = stream.read - data = read(2) - - if len(data) != 2: - raise WebSocketError("Unexpected EOF while decoding header") - - first_byte, second_byte = struct.unpack('!BB', data) - - header = cls( - fin=first_byte & cls.FIN_MASK == cls.FIN_MASK, - opcode=first_byte & cls.OPCODE_MASK, - flags=first_byte & cls.HEADER_FLAG_MASK, - length=second_byte & cls.LENGTH_MASK) - - has_mask = second_byte & cls.MASK_MASK == cls.MASK_MASK - - if header.opcode > 0x07: - if not header.fin: - raise ProtocolError( - "Received fragmented control frame: {0!r}".format(data)) - - # Control frames MUST have a payload length of 125 bytes or less - if header.length > 125: - raise FrameTooLargeException( - "Control frame cannot be larger than 125 bytes: " - "{0!r}".format(data)) - - if header.length == 126: - # 16 bit length - data = read(2) - - if len(data) != 2: - raise WebSocketError('Unexpected EOF while decoding header') - - header.length = struct.unpack('!H', data)[0] - elif header.length == 127: - # 64 bit length - data = read(8) - - if len(data) != 8: - raise WebSocketError('Unexpected EOF while decoding header') - - header.length = struct.unpack('!Q', data)[0] - - if has_mask: - mask = read(4) - - if len(mask) != 4: - raise WebSocketError('Unexpected EOF while decoding header') - - header.mask = mask - - return header - - @classmethod - def encode_header(cls, fin, opcode, mask, length, flags): - """ - Encodes a WebSocket header. - - :param fin: Whether this is the final frame for this opcode. - :param opcode: The opcode of the payload, see `OPCODE_*` - :param mask: Whether the payload is masked. - :param length: The length of the frame. - :param flags: The RSV* flags. - :return: A bytestring encoded header. - """ - first_byte = opcode - second_byte = 0 - extra = b"" - result = bytearray() - - if fin: - first_byte |= cls.FIN_MASK - - if flags & cls.RSV0_MASK: - first_byte |= cls.RSV0_MASK - - if flags & cls.RSV1_MASK: - first_byte |= cls.RSV1_MASK - - if flags & cls.RSV2_MASK: - first_byte |= cls.RSV2_MASK - - # now deal with length complexities - if length < 126: - second_byte += length - elif length <= 0xffff: - second_byte += 126 - extra = struct.pack('!H', length) - elif length <= 0xffffffffffffffff: - second_byte += 127 - extra = struct.pack('!Q', length) - else: - raise FrameTooLargeException - - if mask: - second_byte |= cls.MASK_MASK - - result.append(first_byte) - result.append(second_byte) - result.extend(extra) - - if mask: - result.extend(mask) - - return result diff --git a/src/lib/merkletools/LICENSE b/src/lib/merkletools/LICENSE deleted file mode 100644 index aea5b275..00000000 --- a/src/lib/merkletools/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2016 Tierion - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/src/lib/merkletools/README.md b/src/lib/merkletools/README.md deleted file mode 100644 index 6a160ad4..00000000 --- a/src/lib/merkletools/README.md +++ /dev/null @@ -1,178 +0,0 @@ -# pymerkletools -[![PyPI version](https://badge.fury.io/py/merkletools.svg)](https://badge.fury.io/py/merkletools) [![Build Status](https://travis-ci.org/Tierion/pymerkletools.svg?branch=master)](https://travis-ci.org/Tierion/pymerkletools) - -This is a Python port of [merkle-tools](https://github.com/tierion/merkle-tools). - -Tools for creating Merkle trees, generating merkle proofs, and verification of merkle proofs. - -## Installation - -``` -pip install merkletools -``` - -### Create MerkleTools Object - -```python -import merkletools - -mt = MerkleTools(hash_type="md5") # default is sha256 -# valid hashTypes include all crypto hash algorithms -# such as 'MD5', 'SHA1', 'SHA224', 'SHA256', 'SHA384', 'SHA512' -# as well as the SHA3 family of algorithms -# including 'SHA3-224', 'SHA3-256', 'SHA3-384', and 'SHA3-512' -``` - -To use `sha3`, this module depends on [pysha3](https://pypi.python.org/pypi/pysha3). It will be installed as part of this module or you can install it manually with : -```bash -pip install pysha3==1.0b1 -``` - - -## Methods - -### add_leaf(value, do_hash) - -Adds a value as a leaf or a list of leafs to the tree. The value must be a hex string, otherwise set the optional `do_hash` to true to have your value hashed prior to being added to the tree. - -```python -hex_data = '05ae04314577b2783b4be98211d1b72476c59e9c413cfb2afa2f0c68e0d93911' -list_data = ['Some text data', 'perhaps'] - -mt.add_leaf(hexData) -mt.add_leaf(otherData, True) -``` - -### get_leaf_count() - -Returns the number of leaves that are currently added to the tree. - -```python -leaf_count = mt.get_leaf_count(); -``` - -### get_leaf(index) - -Returns the value of the leaf at the given index as a hex string. - -```python -leaf_value = mt.get_leaf(1) -``` - -### reset_tree() - -Removes all the leaves from the tree, prepararing to to begin creating a new tree. - -```python -mt.reset_tree() -``` - -### make_tree() - -Generates the merkle tree using the leaves that have been added. - -```python -mt.make_tree(); -``` - -### is_ready - -`.is_ready` is a boolean property indicating if the tree is built and ready to supply its root and proofs. The `is_ready` state is `True` only after calling 'make_tree()'. Adding leaves or resetting the tree will change the ready state to False. - -```python -is_ready = mt.is_ready -``` - -### get_merkle_root() - -Returns the merkle root of the tree as a hex string. If the tree is not ready, `None` is returned. - -```python -root_value = mt.get_merkle_root(); -``` - -### get_proof(index) - -Returns the proof as an array of hash objects for the leaf at the given index. If the tree is not ready or no leaf exists at the given index, null is returned. - -```python -proof = mt.get_proof(1) -``` - -The proof array contains a set of merkle sibling objects. Each object contains the sibling hash, with the key value of either right or left. The right or left value tells you where that sibling was in relation to the current hash being evaluated. This information is needed for proof validation, as explained in the following section. - -### validate_proof(proof, target_hash, merkle_root) - -Returns a boolean indicating whether or not the proof is valid and correctly connects the `target_hash` to the `merkle_root`. `proof` is a proof array as supplied by the `get_proof` method. The `target_hash` and `merkle_root` parameters must be a hex strings. - -```python -proof = [ - { right: '09096dbc49b7909917e13b795ebf289ace50b870440f10424af8845fb7761ea5' }, - { right: 'ed2456914e48c1e17b7bd922177291ef8b7f553edf1b1f66b6fc1a076524b22f' }, - { left: 'eac53dde9661daf47a428efea28c81a021c06d64f98eeabbdcff442d992153a8' }, -] -target_hash = '36e0fd847d927d68475f32a94efff30812ee3ce87c7752973f4dd7476aa2e97e' -merkle_root = 'b8b1f39aa2e3fc2dde37f3df04e829f514fb98369b522bfb35c663befa896766' - -is_valid = mt.validate_proof(proof, targetHash, merkleRoot) -``` - -The proof process uses all the proof objects in the array to attempt to prove a relationship between the `target_hash` and the `merkle_root` values. The steps to validate a proof are: - -1. Concatenate `target_hash` and the first hash in the proof array. The right or left designation specifies which side of the concatenation that the proof hash value should be on. -2. Hash the resulting value. -3. Concatenate the resulting hash with the next hash in the proof array, using the same left and right rules. -4. Hash that value and continue the process until you’ve gone through each item in the proof array. -5. The final hash value should equal the `merkle_root` value if the proof is valid, otherwise the proof is invalid. - -## Common Usage - -### Creating a tree and generating the proofs - -```python -mt = MerkleTools() - -mt.add_leaf("tierion", True) -mt.add_leaf(["bitcoin", "blockchain"], True) - -mt.make_tree() - -print "root:", mt.get_merkle_root() # root: '765f15d171871b00034ee55e48ffdf76afbc44ed0bcff5c82f31351d333c2ed1' - -print mt.get_proof(1) # [{left: '2da7240f6c88536be72abe9f04e454c6478ee29709fc3729ddfb942f804fbf08'}, - # {right: 'ef7797e13d3a75526946a3bcf00daec9fc9c9c4d51ddc7cc5df888f74dd434d1'}] - -print mt.validate_proof(mt.get_proof(1), mt.get_leaf(1), mt.get_merkle_root()) # True -``` - -## Notes - -### About tree generation - -1. Internally, leaves are stored as `bytearray`. When the tree is build, it is generated by hashing together the `bytearray` values. -2. Lonely leaf nodes are promoted to the next level up, as depicted below. - - ROOT=Hash(H+E) - / \ - / \ - H=Hash(F+G) E - / \ \ - / \ \ - F=Hash(A+B) G=Hash(C+D) E - / \ / \ \ - / \ / \ \ - A B C D E - - -### Development -This module uses Python's `hashlib` for hashing. Inside a `MerkleTools` object all -hashes are stored as Python `bytearray`. This way hashes can be concatenated simply with `+` and the result -used as input for the hash function. But for -simplicity and easy to use `MerkleTools` methods expect that both input and outputs are hex -strings. We can convert from one type to the other using default Python string methods. -For example: -```python -hash = hashlib.sha256('a').digest() # '\xca\x97\x81\x12\xca\x1b\xbd\xca\xfa\xc21\xb3\x9a#\xdcM\xa7\x86\xef\xf8\x14|Nr\xb9\x80w\x85\xaf\xeeH\xbb' -hex_string = hash.decode('hex') # 'ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb' -back_to_hash = hash_string.decode('hex') # '\xca\x97\x81\x12\xca\x1b\xbd\xca\xfa\xc21\xb3\x9a#\xdcM\xa7\x86\xef\xf8\x14|Nr\xb9\x80w\x85\xaf\xeeH\xbb' -``` diff --git a/src/lib/merkletools/__init__.py b/src/lib/merkletools/__init__.py deleted file mode 100644 index ce5c9487..00000000 --- a/src/lib/merkletools/__init__.py +++ /dev/null @@ -1,138 +0,0 @@ -import hashlib -import binascii - -class MerkleTools(object): - def __init__(self, hash_type="sha256"): - hash_type = hash_type.lower() - if hash_type == 'sha256': - self.hash_function = hashlib.sha256 - elif hash_type == 'md5': - self.hash_function = hashlib.md5 - elif hash_type == 'sha224': - self.hash_function = hashlib.sha224 - elif hash_type == 'sha384': - self.hash_function = hashlib.sha384 - elif hash_type == 'sha512': - self.hash_function = hashlib.sha512 - elif hash_type == 'sha3_256': - self.hash_function = hashlib.sha3_256 - elif hash_type == 'sha3_224': - self.hash_function = hashlib.sha3_224 - elif hash_type == 'sha3_384': - self.hash_function = hashlib.sha3_384 - elif hash_type == 'sha3_512': - self.hash_function = hashlib.sha3_512 - else: - raise Exception('`hash_type` {} nor supported'.format(hash_type)) - - self.reset_tree() - - def _to_hex(self, x): - try: # python3 - return x.hex() - except: # python2 - return binascii.hexlify(x) - - def reset_tree(self): - self.leaves = list() - self.levels = None - self.is_ready = False - - def add_leaf(self, values, do_hash=False): - self.is_ready = False - # check if single leaf - if isinstance(values, tuple) or isinstance(values, list): - for v in values: - if do_hash: - v = v.encode('utf-8') - v = self.hash_function(v).hexdigest() - v = bytearray.fromhex(v) - else: - v = bytearray.fromhex(v) - self.leaves.append(v) - else: - if do_hash: - v = values.encode("utf-8") - v = self.hash_function(v).hexdigest() - v = bytearray.fromhex(v) - else: - v = bytearray.fromhex(values) - self.leaves.append(v) - - def get_leaf(self, index): - return self._to_hex(self.leaves[index]) - - def get_leaf_count(self): - return len(self.leaves) - - def get_tree_ready_state(self): - return self.is_ready - - def _calculate_next_level(self): - solo_leave = None - N = len(self.levels[0]) # number of leaves on the level - if N % 2 == 1: # if odd number of leaves on the level - solo_leave = self.levels[0][-1] - N -= 1 - - new_level = [] - for l, r in zip(self.levels[0][0:N:2], self.levels[0][1:N:2]): - new_level.append(self.hash_function(l+r).digest()) - if solo_leave is not None: - new_level.append(solo_leave) - self.levels = [new_level, ] + self.levels # prepend new level - - def make_tree(self): - self.is_ready = False - if self.get_leaf_count() > 0: - self.levels = [self.leaves, ] - while len(self.levels[0]) > 1: - self._calculate_next_level() - self.is_ready = True - - def get_merkle_root(self): - if self.is_ready: - if self.levels is not None: - return self._to_hex(self.levels[0][0]) - else: - return None - else: - return None - - def get_proof(self, index): - if self.levels is None: - return None - elif not self.is_ready or index > len(self.leaves)-1 or index < 0: - return None - else: - proof = [] - for x in range(len(self.levels) - 1, 0, -1): - level_len = len(self.levels[x]) - if (index == level_len - 1) and (level_len % 2 == 1): # skip if this is an odd end node - index = int(index / 2.) - continue - is_right_node = index % 2 - sibling_index = index - 1 if is_right_node else index + 1 - sibling_pos = "left" if is_right_node else "right" - sibling_value = self._to_hex(self.levels[x][sibling_index]) - proof.append({sibling_pos: sibling_value}) - index = int(index / 2.) - return proof - - def validate_proof(self, proof, target_hash, merkle_root): - merkle_root = bytearray.fromhex(merkle_root) - target_hash = bytearray.fromhex(target_hash) - if len(proof) == 0: - return target_hash == merkle_root - else: - proof_hash = target_hash - for p in proof: - try: - # the sibling is a left node - sibling = bytearray.fromhex(p['left']) - proof_hash = self.hash_function(sibling + proof_hash).digest() - except: - # the sibling is a right node - sibling = bytearray.fromhex(p['right']) - proof_hash = self.hash_function(proof_hash + sibling).digest() - return proof_hash == merkle_root diff --git a/src/lib/merkletools/setup.py b/src/lib/merkletools/setup.py deleted file mode 100644 index 51f2341b..00000000 --- a/src/lib/merkletools/setup.py +++ /dev/null @@ -1,29 +0,0 @@ -import os - -from setuptools import find_packages -from setuptools import setup - -here = os.path.abspath(os.path.dirname(__file__)) -install_requires = [ - "pysha3==1.0b1" -] - -setup( - name='merkletools', - version='1.0.2', - description='Merkle Tools', - classifiers=[ - "Intended Audience :: Developers", - "Intended Audience :: Science/Research", - "License :: OSI Approved :: MIT License", - "Programming Language :: Python :: 2.7", - ], - url='https://github.com/', - author='Eder Santana', - keywords='merkle tree, blockchain, tierion', - license="MIT", - packages=find_packages(), - include_package_data=False, - zip_safe=False, - install_requires=install_requires -) diff --git a/src/lib/opensslVerify/HashInfo.txt b/src/lib/opensslVerify/HashInfo.txt deleted file mode 100644 index 32739d55..00000000 Binary files a/src/lib/opensslVerify/HashInfo.txt and /dev/null differ diff --git a/src/lib/opensslVerify/OpenSSL License.txt b/src/lib/opensslVerify/OpenSSL License.txt deleted file mode 100644 index 3090896c..00000000 --- a/src/lib/opensslVerify/OpenSSL License.txt +++ /dev/null @@ -1,126 +0,0 @@ - - LICENSE ISSUES - ============== - - The OpenSSL toolkit stays under a dual license, i.e. both the conditions of - the OpenSSL License and the original SSLeay license apply to the toolkit. - See below for the actual license texts. Actually both licenses are BSD-style - Open Source licenses. In case of any license issues related to OpenSSL - please contact openssl-core@openssl.org. - - OpenSSL License - --------------- - -/* ==================================================================== - * Copyright (c) 1998-2016 The OpenSSL Project. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" - * - * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For written permission, please contact - * openssl-core@openssl.org. - * - * 5. Products derived from this software may not be called "OpenSSL" - * nor may "OpenSSL" appear in their names without prior written - * permission of the OpenSSL Project. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit (http://www.openssl.org/)" - * - * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This product includes cryptographic software written by Eric Young - * (eay@cryptsoft.com). This product includes software written by Tim - * Hudson (tjh@cryptsoft.com). - * - */ - - Original SSLeay License - ----------------------- - -/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) - * All rights reserved. - * - * This package is an SSL implementation written - * by Eric Young (eay@cryptsoft.com). - * The implementation was written so as to conform with Netscapes SSL. - * - * This library is free for commercial and non-commercial use as long as - * the following conditions are aheared to. The following conditions - * apply to all code found in this distribution, be it the RC4, RSA, - * lhash, DES, etc., code; not just the SSL code. The SSL documentation - * included with this distribution is covered by the same copyright terms - * except that the holder is Tim Hudson (tjh@cryptsoft.com). - * - * Copyright remains Eric Young's, and as such any Copyright notices in - * the code are not to be removed. - * If this package is used in a product, Eric Young should be given attribution - * as the author of the parts of the library used. - * This can be in the form of a textual message at program startup or - * in documentation (online or textual) provided with the package. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * "This product includes cryptographic software written by - * Eric Young (eay@cryptsoft.com)" - * The word 'cryptographic' can be left out if the rouines from the library - * being used are not cryptographic related :-). - * 4. If you include any Windows specific code (or a derivative thereof) from - * the apps directory (application code) you must include an acknowledgement: - * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" - * - * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * The licence and distribution terms for any publically available version or - * derivative of this code cannot be changed. i.e. this code cannot simply be - * copied and put under another distribution licence - * [including the GNU Public Licence.] - */ diff --git a/src/lib/opensslVerify/ReadMe.txt b/src/lib/opensslVerify/ReadMe.txt deleted file mode 100644 index d3acdd9d..00000000 --- a/src/lib/opensslVerify/ReadMe.txt +++ /dev/null @@ -1,59 +0,0 @@ -============================================================================= -OpenSSL v1.0.2l Precompiled Binaries for Win32 ------------------------------------------------------------------------------ - - *** Release Information *** - -Release Date: May 29, 2017 - -Author: Frederik A. Winkelsdorf (opendec.wordpress.com) - for the Indy Project (www.indyproject.org) - -Requirements: Indy 10.5.5+ (SVN Version or Delphi 2009 and newer) - -Dependencies: The libraries have no noteworthy dependencies - -Installation: Copy both DLL files into your application directory - -Supported OS: Windows 2000 up to Windows 10 - ------------------------------------------------------------------------------ - - *** Legal Disclaimer *** - -THIS SOFTWARE IS PROVIDED BY ITS AUTHOR AND THE INDY PROJECT "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -OpenSSL license terms are provided in the file "OpenSSL License.txt". - -PLEASE CHECK IF YOU NEED TO COMPLY WITH EXPORT RESTRICTIONS FOR CRYPTOGRAPHIC -SOFTWARE AND/OR PATENTS. - ------------------------------------------------------------------------------ - - *** Build Information Win32 *** - -Built with: Microsoft Visual C++ 2008 Express Edition - The Netwide Assembler (NASM) v2.11.08 Win32 - Strawberry Perl v5.22.0.1 Win32 Portable - Windows PowerShell - FinalBuilder 7 - -Commands: perl configure VC-WIN32 - ms\do_nasm - adjusted ms\ntdll.mak (replaced "/MD" with "/MT") - adjusted ms\version32.rc (Indy Information inserted) - nmake -f ms\ntdll.mak - nmake -f ms\ntdll.mak test - editbin.exe /rebase:base=0x11000000 libeay32.dll - editbin.exe /rebase:base=0x12000000 ssleay32.dll - -============================================================================= \ No newline at end of file diff --git a/src/lib/opensslVerify/__init__.py b/src/lib/opensslVerify/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/lib/opensslVerify/gencert.cmd b/src/lib/opensslVerify/gencert.cmd deleted file mode 100644 index 105ba6a0..00000000 --- a/src/lib/opensslVerify/gencert.cmd +++ /dev/null @@ -1,10 +0,0 @@ -openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -nodes -config openssl.cnf -REM openssl ecparam -name secp521r1 -genkey -param_enc explicit -out key-ecc.pem -config openssl.cnf - -openssl ecparam -name secp256r1 -genkey -out key-ecc.pem -openssl req -new -key key-ecc.pem -x509 -nodes -out cert-ecc.pem -config openssl.cnf - -@echo off -REM openssl ecparam -genkey -name prime256v1 -out key.pem -REM openssl req -new -key key.pem -out csr.pem -REM openssl req -x509 -days 365 -key key.pem -in csr.pem -out certificate.pem \ No newline at end of file diff --git a/src/lib/opensslVerify/libeay32.dll b/src/lib/opensslVerify/libeay32.dll deleted file mode 100644 index b66c6bbd..00000000 Binary files a/src/lib/opensslVerify/libeay32.dll and /dev/null differ diff --git a/src/lib/opensslVerify/license.txt b/src/lib/opensslVerify/license.txt deleted file mode 100644 index fb03713d..00000000 --- a/src/lib/opensslVerify/license.txt +++ /dev/null @@ -1,127 +0,0 @@ - - LICENSE ISSUES - ============== - - The OpenSSL toolkit stays under a dual license, i.e. both the conditions of - the OpenSSL License and the original SSLeay license apply to the toolkit. - See below for the actual license texts. Actually both licenses are BSD-style - Open Source licenses. In case of any license issues related to OpenSSL - please contact openssl-core@openssl.org. - - OpenSSL License - --------------- - -/* ==================================================================== - * Copyright (c) 1998-2016 The OpenSSL Project. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" - * - * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For written permission, please contact - * openssl-core@openssl.org. - * - * 5. Products derived from this software may not be called "OpenSSL" - * nor may "OpenSSL" appear in their names without prior written - * permission of the OpenSSL Project. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit (http://www.openssl.org/)" - * - * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This product includes cryptographic software written by Eric Young - * (eay@cryptsoft.com). This product includes software written by Tim - * Hudson (tjh@cryptsoft.com). - * - */ - - Original SSLeay License - ----------------------- - -/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) - * All rights reserved. - * - * This package is an SSL implementation written - * by Eric Young (eay@cryptsoft.com). - * The implementation was written so as to conform with Netscapes SSL. - * - * This library is free for commercial and non-commercial use as long as - * the following conditions are aheared to. The following conditions - * apply to all code found in this distribution, be it the RC4, RSA, - * lhash, DES, etc., code; not just the SSL code. The SSL documentation - * included with this distribution is covered by the same copyright terms - * except that the holder is Tim Hudson (tjh@cryptsoft.com). - * - * Copyright remains Eric Young's, and as such any Copyright notices in - * the code are not to be removed. - * If this package is used in a product, Eric Young should be given attribution - * as the author of the parts of the library used. - * This can be in the form of a textual message at program startup or - * in documentation (online or textual) provided with the package. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * "This product includes cryptographic software written by - * Eric Young (eay@cryptsoft.com)" - * The word 'cryptographic' can be left out if the rouines from the library - * being used are not cryptographic related :-). - * 4. If you include any Windows specific code (or a derivative thereof) from - * the apps directory (application code) you must include an acknowledgement: - * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" - * - * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * The licence and distribution terms for any publically available version or - * derivative of this code cannot be changed. i.e. this code cannot simply be - * copied and put under another distribution licence - * [including the GNU Public Licence.] - */ - diff --git a/src/lib/opensslVerify/openssl.cnf b/src/lib/opensslVerify/openssl.cnf deleted file mode 100644 index a2c48ba1..00000000 --- a/src/lib/opensslVerify/openssl.cnf +++ /dev/null @@ -1,70 +0,0 @@ -[ req ] -prompt = no -default_bits = 2048 -default_keyfile = server-key.pem -distinguished_name = subject -req_extensions = req_ext -x509_extensions = x509_ext -string_mask = utf8only - -# The Subject DN can be formed using X501 or RFC 4514 (see RFC 4519 for a description). -# Its sort of a mashup. For example, RFC 4514 does not provide emailAddress. -[ subject ] -countryName = US -stateOrProvinceName = NY -localityName = New York -organizationName = Example, LLC - -# Use a friendly name here because its presented to the user. The server's DNS -# names are placed in Subject Alternate Names. Plus, DNS names here is deprecated -# by both IETF and CA/Browser Forums. If you place a DNS name here, then you -# must include the DNS name in the SAN too (otherwise, Chrome and others that -# strictly follow the CA/Browser Baseline Requirements will fail). -commonName = Example Company - -emailAddress = test@example.com - -# Section x509_ext is used when generating a self-signed certificate. I.e., openssl req -x509 ... -[ x509_ext ] - -subjectKeyIdentifier = hash -authorityKeyIdentifier = keyid,issuer - -basicConstraints = CA:FALSE -keyUsage = digitalSignature, keyEncipherment -subjectAltName = @alternate_names -nsComment = "OpenSSL Generated Certificate" - -# RFC 5280, Section 4.2.1.12 makes EKU optional -# CA/Browser Baseline Requirements, Appendix (B)(3)(G) makes me confused -# extendedKeyUsage = serverAuth, clientAuth - -# Section req_ext is used when generating a certificate signing request. I.e., openssl req ... -[ req_ext ] - -subjectKeyIdentifier = hash - -basicConstraints = CA:FALSE -keyUsage = digitalSignature, keyEncipherment -subjectAltName = @alternate_names -nsComment = "OpenSSL Generated Certificate" - -# RFC 5280, Section 4.2.1.12 makes EKU optional -# CA/Browser Baseline Requirements, Appendix (B)(3)(G) makes me confused -# extendedKeyUsage = serverAuth, clientAuth - -[ alternate_names ] - -DNS.1 = example.com -DNS.2 = www.example.com -DNS.3 = mail.example.com -DNS.4 = ftp.example.com - -# Add these if you need them. But usually you don't want them or -# need them in production. You may need them for development. -# DNS.5 = localhost -# DNS.6 = localhost.localdomain -# DNS.7 = 127.0.0.1 - -# IPv6 localhost -# DNS.8 = ::1 \ No newline at end of file diff --git a/src/lib/opensslVerify/openssl.exe b/src/lib/opensslVerify/openssl.exe deleted file mode 100644 index 7bdac04f..00000000 Binary files a/src/lib/opensslVerify/openssl.exe and /dev/null differ diff --git a/src/lib/opensslVerify/opensslVerify.py b/src/lib/opensslVerify/opensslVerify.py deleted file mode 100644 index 524aeb4d..00000000 --- a/src/lib/opensslVerify/opensslVerify.py +++ /dev/null @@ -1,455 +0,0 @@ -# via http://pastebin.com/H1XikJFd -# -*- Mode: Python -*- - -# This is a combination of http://pastebin.com/bQtdDzHx and -# https://github.com/Bitmessage/PyBitmessage/blob/master/src/pyelliptic/openssl.py -# that doesn't crash on OSX. -# Long message bug fixed by ZeroNet - -import ctypes -import ctypes.util -import _ctypes -import hashlib -import base64 -import time -import logging -import sys -import os - -addrtype = 0 - - -class _OpenSSL: - - """ - Wrapper for OpenSSL using ctypes - """ - - def __init__(self, library): - self.time_opened = time.time() - """ - Build the wrapper - """ - try: - self._lib = ctypes.CDLL(library) - except: - self._lib = ctypes.cdll.LoadLibrary(library) - - self.pointer = ctypes.pointer - self.c_int = ctypes.c_int - self.byref = ctypes.byref - self.create_string_buffer = ctypes.create_string_buffer - - self.BN_new = self._lib.BN_new - self.BN_new.restype = ctypes.c_void_p - self.BN_new.argtypes = [] - - self.BN_copy = self._lib.BN_copy - self.BN_copy.restype = ctypes.c_void_p - self.BN_copy.argtypes = [ctypes.c_void_p, ctypes.c_void_p] - - self.BN_mul_word = self._lib.BN_mul_word - self.BN_mul_word.restype = ctypes.c_int - self.BN_mul_word.argtypes = [ctypes.c_void_p, ctypes.c_int] - - self.BN_set_word = self._lib.BN_set_word - self.BN_set_word.restype = ctypes.c_int - self.BN_set_word.argtypes = [ctypes.c_void_p, ctypes.c_int] - - self.BN_add = self._lib.BN_add - self.BN_add.restype = ctypes.c_void_p - self.BN_add.argtypes = [ctypes.c_void_p, ctypes.c_void_p, - ctypes.c_void_p] - - self.BN_mod_sub = self._lib.BN_mod_sub - self.BN_mod_sub.restype = ctypes.c_int - self.BN_mod_sub.argtypes = [ctypes.c_void_p, ctypes.c_void_p, - ctypes.c_void_p, - ctypes.c_void_p, - ctypes.c_void_p] - - self.BN_mod_mul = self._lib.BN_mod_mul - self.BN_mod_mul.restype = ctypes.c_int - self.BN_mod_mul.argtypes = [ctypes.c_void_p, ctypes.c_void_p, - ctypes.c_void_p, - ctypes.c_void_p, - ctypes.c_void_p] - - self.BN_mod_inverse = self._lib.BN_mod_inverse - self.BN_mod_inverse.restype = ctypes.c_void_p - self.BN_mod_inverse.argtypes = [ctypes.c_void_p, ctypes.c_void_p, - ctypes.c_void_p, - ctypes.c_void_p] - - self.BN_cmp = self._lib.BN_cmp - self.BN_cmp.restype = ctypes.c_int - self.BN_cmp.argtypes = [ctypes.c_void_p, ctypes.c_void_p] - - self.BN_bn2bin = self._lib.BN_bn2bin - self.BN_bn2bin.restype = ctypes.c_int - self.BN_bn2bin.argtypes = [ctypes.c_void_p, ctypes.c_void_p] - - self.BN_bin2bn = self._lib.BN_bin2bn - self.BN_bin2bn.restype = ctypes.c_void_p - self.BN_bin2bn.argtypes = [ctypes.c_void_p, ctypes.c_int, - ctypes.c_void_p] - - self.EC_KEY_new_by_curve_name = self._lib.EC_KEY_new_by_curve_name - self.EC_KEY_new_by_curve_name.restype = ctypes.c_void_p - self.EC_KEY_new_by_curve_name.argtypes = [ctypes.c_int] - - self.EC_KEY_get0_group = self._lib.EC_KEY_get0_group - self.EC_KEY_get0_group.restype = ctypes.c_void_p - self.EC_KEY_get0_group.argtypes = [ctypes.c_void_p] - - self.EC_KEY_set_private_key = self._lib.EC_KEY_set_private_key - self.EC_KEY_set_private_key.restype = ctypes.c_int - self.EC_KEY_set_private_key.argtypes = [ctypes.c_void_p, - ctypes.c_void_p] - - self.EC_KEY_set_public_key = self._lib.EC_KEY_set_public_key - self.EC_KEY_set_public_key.restype = ctypes.c_int - self.EC_KEY_set_public_key.argtypes = [ctypes.c_void_p, - ctypes.c_void_p] - - self.EC_POINT_set_compressed_coordinates_GFp = self._lib.EC_POINT_set_compressed_coordinates_GFp - self.EC_POINT_set_compressed_coordinates_GFp.restype = ctypes.c_int - self.EC_POINT_set_compressed_coordinates_GFp.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p] - - self.EC_POINT_new = self._lib.EC_POINT_new - self.EC_POINT_new.restype = ctypes.c_void_p - self.EC_POINT_new.argtypes = [ctypes.c_void_p] - - self.EC_POINT_free = self._lib.EC_POINT_free - self.EC_POINT_free.restype = None - self.EC_POINT_free.argtypes = [ctypes.c_void_p] - - self.EC_GROUP_get_order = self._lib.EC_GROUP_get_order - self.EC_GROUP_get_order.restype = ctypes.c_void_p - self.EC_GROUP_get_order.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p] - - self.EC_GROUP_get_degree = self._lib.EC_GROUP_get_degree - self.EC_GROUP_get_degree.restype = ctypes.c_void_p - self.EC_GROUP_get_degree.argtypes = [ctypes.c_void_p] - - self.EC_GROUP_get_curve_GFp = self._lib.EC_GROUP_get_curve_GFp - self.EC_GROUP_get_curve_GFp.restype = ctypes.c_void_p - self.EC_GROUP_get_curve_GFp.argtypes = [ctypes.c_void_p, - ctypes.c_void_p, - ctypes.c_void_p, - ctypes.c_void_p, - ctypes.c_void_p] - - self.EC_POINT_mul = self._lib.EC_POINT_mul - self.EC_POINT_mul.restype = ctypes.c_int - self.EC_POINT_mul.argtypes = [ctypes.c_void_p, ctypes.c_void_p, - ctypes.c_void_p, ctypes.c_void_p, - ctypes.c_void_p, ctypes.c_void_p] - - self.EC_KEY_set_private_key = self._lib.EC_KEY_set_private_key - self.EC_KEY_set_private_key.restype = ctypes.c_int - self.EC_KEY_set_private_key.argtypes = [ctypes.c_void_p, - ctypes.c_void_p] - - self.EC_KEY_set_conv_form = self._lib.EC_KEY_set_conv_form - self.EC_KEY_set_conv_form.restype = None - self.EC_KEY_set_conv_form.argtypes = [ctypes.c_void_p, - ctypes.c_int] - - self.BN_CTX_new = self._lib.BN_CTX_new - self._lib.BN_CTX_new.restype = ctypes.c_void_p - self._lib.BN_CTX_new.argtypes = [] - - self.BN_CTX_start = self._lib.BN_CTX_start - self._lib.BN_CTX_start.restype = ctypes.c_void_p - self._lib.BN_CTX_start.argtypes = [ctypes.c_void_p] - - self.BN_CTX_get = self._lib.BN_CTX_get - self._lib.BN_CTX_get.restype = ctypes.c_void_p - self._lib.BN_CTX_get.argtypes = [ctypes.c_void_p] - - self.ECDSA_sign = self._lib.ECDSA_sign - self.ECDSA_sign.restype = ctypes.c_int - self.ECDSA_sign.argtypes = [ctypes.c_int, ctypes.c_void_p, - ctypes.c_int, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p] - - self.ECDSA_verify = self._lib.ECDSA_verify - self.ECDSA_verify.restype = ctypes.c_int - self.ECDSA_verify.argtypes = [ctypes.c_int, ctypes.c_void_p, - ctypes.c_int, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p] - - self.i2o_ECPublicKey = self._lib.i2o_ECPublicKey - self.i2o_ECPublicKey.restype = ctypes.c_void_p - self.i2o_ECPublicKey.argtypes = [ctypes.c_void_p, ctypes.c_void_p] - - self.BN_CTX_free = self._lib.BN_CTX_free - self.BN_CTX_free.restype = None - self.BN_CTX_free.argtypes = [ctypes.c_void_p] - - self.EC_POINT_free = self._lib.EC_POINT_free - self.EC_POINT_free.restype = None - self.EC_POINT_free.argtypes = [ctypes.c_void_p] - -ssl = None - -def openLibrary(): - global ssl - import util.SslPatch - ssl = _OpenSSL(util.SslPatch.getLibraryPath()) - logging.debug("opensslVerify loaded: %s", ssl._lib) - -if __name__ == "__main__": - ssl = _OpenSSL(sys.argv[1]) -else: - openLibrary() - -openssl_version = "%.9X" % ssl._lib.SSLeay() - -NID_secp256k1 = 714 - - -def check_result(val, func, args): - if val == 0: - raise ValueError - else: - return ctypes.c_void_p(val) - -ssl.EC_KEY_new_by_curve_name.restype = ctypes.c_void_p -ssl.EC_KEY_new_by_curve_name.errcheck = check_result - -POINT_CONVERSION_COMPRESSED = 2 -POINT_CONVERSION_UNCOMPRESSED = 4 - -__b58chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' -__b58base = len(__b58chars) - - -def b58encode(v): - """ encode v, which is a string of bytes, to base58. - """ - - long_value = 0L - for (i, c) in enumerate(v[::-1]): - long_value += (256 ** i) * ord(c) - - result = '' - while long_value >= __b58base: - div, mod = divmod(long_value, __b58base) - result = __b58chars[mod] + result - long_value = div - result = __b58chars[long_value] + result - - # Bitcoin does a little leading-zero-compression: - # leading 0-bytes in the input become leading-1s - nPad = 0 - for c in v: - if c == '\0': - nPad += 1 - else: - break - - return (__b58chars[0] * nPad) + result - - -def hash_160(public_key): - md = hashlib.new('ripemd160') - md.update(hashlib.sha256(public_key).digest()) - return md.digest() - - -def hash_160_to_bc_address(h160): - vh160 = chr(addrtype) + h160 - h = Hash(vh160) - addr = vh160 + h[0:4] - return b58encode(addr) - - -def public_key_to_bc_address(public_key): - h160 = hash_160(public_key) - return hash_160_to_bc_address(h160) - - -def encode(val, base, minlen=0): - base, minlen = int(base), int(minlen) - code_string = ''.join([chr(x) for x in range(256)]) - result = "" - while val > 0: - result = code_string[val % base] + result - val //= base - return code_string[0] * max(minlen - len(result), 0) + result - - -def num_to_var_int(x): - x = int(x) - if x < 253: - return chr(x) - elif x < 65536: - return chr(253) + encode(x, 256, 2)[::-1] - elif x < 4294967296: - return chr(254) + encode(x, 256, 4)[::-1] - else: - return chr(255) + encode(x, 256, 8)[::-1] - - -def msg_magic(message): - return "\x18Bitcoin Signed Message:\n" + num_to_var_int(len(message)) + message - - -def get_address(eckey): - size = ssl.i2o_ECPublicKey(eckey, 0) - mb = ctypes.create_string_buffer(size) - ssl.i2o_ECPublicKey(eckey, ctypes.byref(ctypes.pointer(mb))) - return public_key_to_bc_address(mb.raw) - - -def Hash(data): - return hashlib.sha256(hashlib.sha256(data).digest()).digest() - - -def bx(bn, size=32): - b = ctypes.create_string_buffer(size) - ssl.BN_bn2bin(bn, b) - return b.raw.encode('hex') - - -def verify_message(address, signature, message): - pkey = ssl.EC_KEY_new_by_curve_name(NID_secp256k1) - eckey = SetCompactSignature(pkey, Hash(msg_magic(message)), signature) - addr = get_address(eckey) - return (address == addr) - - -def SetCompactSignature(pkey, hash, signature): - sig = base64.b64decode(signature) - if len(sig) != 65: - raise Exception("Wrong encoding") - nV = ord(sig[0]) - if nV < 27 or nV >= 35: - return False - if nV >= 31: - ssl.EC_KEY_set_conv_form(pkey, POINT_CONVERSION_COMPRESSED) - nV -= 4 - r = ssl.BN_bin2bn(sig[1:33], 32, None) - s = ssl.BN_bin2bn(sig[33:], 32, None) - eckey = ECDSA_SIG_recover_key_GFp(pkey, r, s, hash, len(hash), nV - 27, - False) - return eckey - - -def ECDSA_SIG_recover_key_GFp(eckey, r, s, msg, msglen, recid, check): - n = 0 - i = recid / 2 - ctx = R = O = Q = None - - try: - group = ssl.EC_KEY_get0_group(eckey) - ctx = ssl.BN_CTX_new() - ssl.BN_CTX_start(ctx) - order = ssl.BN_CTX_get(ctx) - ssl.EC_GROUP_get_order(group, order, ctx) - x = ssl.BN_CTX_get(ctx) - ssl.BN_copy(x, order) - ssl.BN_mul_word(x, i) - ssl.BN_add(x, x, r) - field = ssl.BN_CTX_get(ctx) - ssl.EC_GROUP_get_curve_GFp(group, field, None, None, ctx) - - if (ssl.BN_cmp(x, field) >= 0): - return False - - R = ssl.EC_POINT_new(group) - ssl.EC_POINT_set_compressed_coordinates_GFp(group, R, x, recid % 2, ctx) - - if check: - O = ssl.EC_POINT_new(group) - ssl.EC_POINT_mul(group, O, None, R, order, ctx) - if ssl.EC_POINT_is_at_infinity(group, O): - return False - - Q = ssl.EC_POINT_new(group) - n = ssl.EC_GROUP_get_degree(group) - e = ssl.BN_CTX_get(ctx) - ssl.BN_bin2bn(msg, msglen, e) - if 8 * msglen > n: - ssl.BN_rshift(e, e, 8 - (n & 7)) - - zero = ssl.BN_CTX_get(ctx) - ssl.BN_set_word(zero, 0) - ssl.BN_mod_sub(e, zero, e, order, ctx) - rr = ssl.BN_CTX_get(ctx) - ssl.BN_mod_inverse(rr, r, order, ctx) - sor = ssl.BN_CTX_get(ctx) - ssl.BN_mod_mul(sor, s, rr, order, ctx) - eor = ssl.BN_CTX_get(ctx) - ssl.BN_mod_mul(eor, e, rr, order, ctx) - ssl.EC_POINT_mul(group, Q, eor, R, sor, ctx) - ssl.EC_KEY_set_public_key(eckey, Q) - return eckey - finally: - if ctx: - ssl.BN_CTX_free(ctx) - if R: - ssl.EC_POINT_free(R) - if O: - ssl.EC_POINT_free(O) - if Q: - ssl.EC_POINT_free(Q) - - -def closeLibrary(): - handle = ssl._lib._handle - if "FreeLibrary" in dir(_ctypes): - _ctypes.FreeLibrary(handle) - _ctypes.FreeLibrary(handle) - print "OpenSSL closed, handle:", handle - else: - _ctypes.dlclose(handle) - _ctypes.dlclose(handle) - print "OpenSSL dlclosed, handle:", handle - - -def getMessagePubkey(message, sig): - pkey = ssl.EC_KEY_new_by_curve_name(NID_secp256k1) - if type(pkey) is not int and not pkey.value: - raise Exception( - "OpenSSL %s (%s) EC_KEY_new_by_curve_name failed: %s, probably your OpenSSL lib does not support secp256k1 elliptic curve. Please check: https://github.com/HelloZeroNet/ZeroNet/issues/132" % - (openssl_version, ssl._lib._name, pkey.value) - ) - eckey = SetCompactSignature(pkey, Hash(msg_magic(message)), sig) - size = ssl.i2o_ECPublicKey(eckey, 0) - mb = ctypes.create_string_buffer(size) - ssl.i2o_ECPublicKey(eckey, ctypes.byref(ctypes.pointer(mb))) - pub = mb.raw - """ - if time.time() - ssl.time_opened > 60 * 5: # Reopen every 5 min - logging.debug("Reopening OpenSSL...") - closeLibrary() - openLibrary() - """ - return pub - - -def test(): - sign = "HGbib2kv9gm9IJjDt1FXbXFczZi35u0rZR3iPUIt5GglDDCeIQ7v8eYXVNIaLoJRI4URGZrhwmsYQ9aVtRTnTfQ=" - pubkey = "044827c756561b8ef6b28b5e53a000805adbf4938ab82e1c2b7f7ea16a0d6face9a509a0a13e794d742210b00581f3e249ebcc705240af2540ea19591091ac1d41" - assert getMessagePubkey("hello", sign).encode("hex") == pubkey - -test() # Make sure it working right - -if __name__ == "__main__": - import time - import os - import sys - sys.path.append("../pybitcointools") - import bitcoin as btctools - print "OpenSSL version %s" % openssl_version - print ssl._lib - priv = "5JsunC55XGVqFQj5kPGK4MWgTL26jKbnPhjnmchSNPo75XXCwtk" - address = "1N2XWu5soeppX2qUjvrf81rpdbShKJrjTr" - sign = btctools.ecdsa_sign("hello", priv) # HGbib2kv9gm9IJjDt1FXbXFczZi35u0rZR3iPUIt5GglDDCeIQ7v8eYXVNIaLoJRI4URGZrhwmsYQ9aVtRTnTfQ= - - s = time.time() - for i in range(1000): - pubkey = getMessagePubkey("hello", sign) - verified = btctools.pubkey_to_address(pubkey) == address - print "1000x Verified", verified, time.time() - s diff --git a/src/lib/opensslVerify/ssleay32.dll b/src/lib/opensslVerify/ssleay32.dll deleted file mode 100644 index 2ebf965d..00000000 Binary files a/src/lib/opensslVerify/ssleay32.dll and /dev/null differ diff --git a/src/lib/pyasn1/LICENSE.rst b/src/lib/pyasn1/LICENSE.rst deleted file mode 100644 index 02b45c43..00000000 --- a/src/lib/pyasn1/LICENSE.rst +++ /dev/null @@ -1,24 +0,0 @@ -Copyright (c) 2005-2017, Ilya Etingof -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. diff --git a/src/lib/pyasn1/__init__.py b/src/lib/pyasn1/__init__.py deleted file mode 100644 index 091f6c3c..00000000 --- a/src/lib/pyasn1/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -import sys - -# http://www.python.org/dev/peps/pep-0396/ -__version__ = '0.2.4' - -if sys.version_info[:2] < (2, 4): - raise RuntimeError('PyASN1 requires Python 2.4 or later') - diff --git a/src/lib/pyasn1/codec/__init__.py b/src/lib/pyasn1/codec/__init__.py deleted file mode 100644 index 8c3066b2..00000000 --- a/src/lib/pyasn1/codec/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# This file is necessary to make this directory a package. diff --git a/src/lib/pyasn1/codec/ber/__init__.py b/src/lib/pyasn1/codec/ber/__init__.py deleted file mode 100644 index 8c3066b2..00000000 --- a/src/lib/pyasn1/codec/ber/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# This file is necessary to make this directory a package. diff --git a/src/lib/pyasn1/codec/ber/decoder.py b/src/lib/pyasn1/codec/ber/decoder.py deleted file mode 100644 index e100e750..00000000 --- a/src/lib/pyasn1/codec/ber/decoder.py +++ /dev/null @@ -1,1048 +0,0 @@ -# -# This file is part of pyasn1 software. -# -# Copyright (c) 2005-2017, Ilya Etingof -# License: http://pyasn1.sf.net/license.html -# -from pyasn1.type import base, tag, univ, char, useful, tagmap -from pyasn1.codec.ber import eoo -from pyasn1.compat.octets import oct2int, octs2ints, ints2octs, ensureString, null -from pyasn1.compat.integer import from_bytes -from pyasn1 import debug, error - -__all__ = ['decode'] - - -class AbstractDecoder(object): - protoComponent = None - - def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): - raise error.PyAsn1Error('Decoder not implemented for %s' % (tagSet,)) - - def indefLenValueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): - raise error.PyAsn1Error('Indefinite length mode decoder not implemented for %s' % (tagSet,)) - - -class AbstractSimpleDecoder(AbstractDecoder): - tagFormats = (tag.tagFormatSimple,) - - @staticmethod - def substrateCollector(asn1Object, substrate, length): - return substrate[:length], substrate[length:] - - def _createComponent(self, asn1Spec, tagSet, value=None): - if tagSet[0].tagFormat not in self.tagFormats: - raise error.PyAsn1Error('Invalid tag format %s for %s' % (tagSet[0], self.protoComponent.prettyPrintType())) - if asn1Spec is None: - return self.protoComponent.clone(value, tagSet) - elif value is None: - return asn1Spec - else: - return asn1Spec.clone(value) - - -class AbstractConstructedDecoder(AbstractDecoder): - tagFormats = (tag.tagFormatConstructed,) - - # noinspection PyUnusedLocal - def _createComponent(self, asn1Spec, tagSet, value=None): - if tagSet[0].tagFormat not in self.tagFormats: - raise error.PyAsn1Error('Invalid tag format %s for %s' % (tagSet[0], self.protoComponent.prettyPrintType())) - if asn1Spec is None: - return self.protoComponent.clone(tagSet) - else: - return asn1Spec.clone() - - -class ExplicitTagDecoder(AbstractSimpleDecoder): - protoComponent = univ.Any('') - tagFormats = (tag.tagFormatConstructed,) - - def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): - if substrateFun: - return substrateFun( - self._createComponent(asn1Spec, tagSet, ''), - substrate, length - ) - head, tail = substrate[:length], substrate[length:] - value, _ = decodeFun(head, asn1Spec, tagSet, length) - return value, tail - - def indefLenValueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): - if substrateFun: - return substrateFun( - self._createComponent(asn1Spec, tagSet, ''), - substrate, length - ) - value, substrate = decodeFun(substrate, asn1Spec, tagSet, length) - terminator, substrate = decodeFun(substrate, allowEoo=True) - if terminator is eoo.endOfOctets: - return value, substrate - else: - raise error.PyAsn1Error('Missing end-of-octets terminator') - - -explicitTagDecoder = ExplicitTagDecoder() - - -class IntegerDecoder(AbstractSimpleDecoder): - protoComponent = univ.Integer(0) - - def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, length, - state, decodeFun, substrateFun): - head, tail = substrate[:length], substrate[length:] - - if not head: - return self._createComponent(asn1Spec, tagSet, 0), tail - - value = from_bytes(head, signed=True) - - return self._createComponent(asn1Spec, tagSet, value), tail - - -class BooleanDecoder(IntegerDecoder): - protoComponent = univ.Boolean(0) - - def _createComponent(self, asn1Spec, tagSet, value=None): - return IntegerDecoder._createComponent(self, asn1Spec, tagSet, value and 1 or 0) - - -class BitStringDecoder(AbstractSimpleDecoder): - protoComponent = univ.BitString(()) - tagFormats = (tag.tagFormatSimple, tag.tagFormatConstructed) - supportConstructedForm = True - - def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, length, - state, decodeFun, substrateFun): - head, tail = substrate[:length], substrate[length:] - if tagSet[0].tagFormat == tag.tagFormatSimple: # XXX what tag to check? - if not head: - raise error.PyAsn1Error('Empty substrate') - trailingBits = oct2int(head[0]) - if trailingBits > 7: - raise error.PyAsn1Error( - 'Trailing bits overflow %s' % trailingBits - ) - head = head[1:] - value = self.protoComponent.fromOctetString(head, trailingBits) - return self._createComponent(asn1Spec, tagSet, value), tail - - if not self.supportConstructedForm: - raise error.PyAsn1Error('Constructed encoding form prohibited at %s' % self.__class__.__name__) - - bitString = self._createComponent(asn1Spec, tagSet) - - if substrateFun: - return substrateFun(bitString, substrate, length) - - while head: - component, head = decodeFun(head, self.protoComponent) - bitString += component - - return bitString, tail - - def indefLenValueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): - bitString = self._createComponent(asn1Spec, tagSet) - - if substrateFun: - return substrateFun(bitString, substrate, length) - - while substrate: - component, substrate = decodeFun(substrate, self.protoComponent, allowEoo=True) - if component is eoo.endOfOctets: - break - - bitString += component - - else: - raise error.SubstrateUnderrunError('No EOO seen before substrate ends') - - return bitString, substrate - - -class OctetStringDecoder(AbstractSimpleDecoder): - protoComponent = univ.OctetString('') - tagFormats = (tag.tagFormatSimple, tag.tagFormatConstructed) - supportConstructedForm = True - - def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, length, - state, decodeFun, substrateFun): - head, tail = substrate[:length], substrate[length:] - - if substrateFun: - return substrateFun(self._createComponent(asn1Spec, tagSet), - substrate, length) - - if tagSet[0].tagFormat == tag.tagFormatSimple: # XXX what tag to check? - return self._createComponent(asn1Spec, tagSet, head), tail - - if not self.supportConstructedForm: - raise error.PyAsn1Error('Constructed encoding form prohibited at %s' % self.__class__.__name__) - - # All inner fragments are of the same type, treat them as octet string - substrateFun = self.substrateCollector - - header = null - - while head: - component, head = decodeFun(head, self.protoComponent, - substrateFun=substrateFun) - header += component - - return self._createComponent(asn1Spec, tagSet, header), tail - - def indefLenValueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): - if substrateFun and substrateFun is not self.substrateCollector: - asn1Object = self._createComponent(asn1Spec, tagSet) - return substrateFun(asn1Object, substrate, length) - - # All inner fragments are of the same type, treat them as octet string - substrateFun = self.substrateCollector - - header = null - - while substrate: - component, substrate = decodeFun(substrate, - self.protoComponent, - substrateFun=substrateFun, - allowEoo=True) - if component is eoo.endOfOctets: - break - header += component - else: - raise error.SubstrateUnderrunError( - 'No EOO seen before substrate ends' - ) - return self._createComponent(asn1Spec, tagSet, header), substrate - - -class NullDecoder(AbstractSimpleDecoder): - protoComponent = univ.Null('') - - def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): - head, tail = substrate[:length], substrate[length:] - component = self._createComponent(asn1Spec, tagSet) - if head: - raise error.PyAsn1Error('Unexpected %d-octet substrate for Null' % length) - return component, tail - - -class ObjectIdentifierDecoder(AbstractSimpleDecoder): - protoComponent = univ.ObjectIdentifier(()) - - def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, length, - state, decodeFun, substrateFun): - head, tail = substrate[:length], substrate[length:] - if not head: - raise error.PyAsn1Error('Empty substrate') - - head = octs2ints(head) - - oid = () - index = 0 - substrateLen = len(head) - while index < substrateLen: - subId = head[index] - index += 1 - if subId < 128: - oid = oid + (subId,) - elif subId > 128: - # Construct subid from a number of octets - nextSubId = subId - subId = 0 - while nextSubId >= 128: - subId = (subId << 7) + (nextSubId & 0x7F) - if index >= substrateLen: - raise error.SubstrateUnderrunError( - 'Short substrate for sub-OID past %s' % (oid,) - ) - nextSubId = head[index] - index += 1 - oid += ((subId << 7) + nextSubId,) - elif subId == 128: - # ASN.1 spec forbids leading zeros (0x80) in OID - # encoding, tolerating it opens a vulnerability. See - # http://www.cosic.esat.kuleuven.be/publications/article-1432.pdf - # page 7 - raise error.PyAsn1Error('Invalid octet 0x80 in OID encoding') - - # Decode two leading arcs - if 0 <= oid[0] <= 39: - oid = (0,) + oid - elif 40 <= oid[0] <= 79: - oid = (1, oid[0] - 40) + oid[1:] - elif oid[0] >= 80: - oid = (2, oid[0] - 80) + oid[1:] - else: - raise error.PyAsn1Error('Malformed first OID octet: %s' % head[0]) - - return self._createComponent(asn1Spec, tagSet, oid), tail - - -class RealDecoder(AbstractSimpleDecoder): - protoComponent = univ.Real() - - def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): - head, tail = substrate[:length], substrate[length:] - if not head: - return self._createComponent(asn1Spec, tagSet, 0.0), tail - fo = oct2int(head[0]) - head = head[1:] - if fo & 0x80: # binary encoding - if not head: - raise error.PyAsn1Error("Incomplete floating-point value") - n = (fo & 0x03) + 1 - if n == 4: - n = oct2int(head[0]) - head = head[1:] - eo, head = head[:n], head[n:] - if not eo or not head: - raise error.PyAsn1Error('Real exponent screwed') - e = oct2int(eo[0]) & 0x80 and -1 or 0 - while eo: # exponent - e <<= 8 - e |= oct2int(eo[0]) - eo = eo[1:] - b = fo >> 4 & 0x03 # base bits - if b > 2: - raise error.PyAsn1Error('Illegal Real base') - if b == 1: # encbase = 8 - e *= 3 - elif b == 2: # encbase = 16 - e *= 4 - p = 0 - while head: # value - p <<= 8 - p |= oct2int(head[0]) - head = head[1:] - if fo & 0x40: # sign bit - p = -p - sf = fo >> 2 & 0x03 # scale bits - p *= 2 ** sf - value = (p, 2, e) - elif fo & 0x40: # infinite value - value = fo & 0x01 and '-inf' or 'inf' - elif fo & 0xc0 == 0: # character encoding - if not head: - raise error.PyAsn1Error("Incomplete floating-point value") - try: - if fo & 0x3 == 0x1: # NR1 - value = (int(head), 10, 0) - elif fo & 0x3 == 0x2: # NR2 - value = float(head) - elif fo & 0x3 == 0x3: # NR3 - value = float(head) - else: - raise error.SubstrateUnderrunError( - 'Unknown NR (tag %s)' % fo - ) - except ValueError: - raise error.SubstrateUnderrunError( - 'Bad character Real syntax' - ) - else: - raise error.SubstrateUnderrunError( - 'Unknown encoding (tag %s)' % fo - ) - return self._createComponent(asn1Spec, tagSet, value), tail - - -class SequenceAndSetDecoderBase(AbstractConstructedDecoder): - protoComponent = None - orderedComponents = False - - def _getComponentTagMap(self, asn1Object, idx): - raise NotImplementedError() - - def _getComponentPositionByType(self, asn1Object, tagSet, idx): - raise NotImplementedError() - - def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): - head, tail = substrate[:length], substrate[length:] - asn1Object = self._createComponent(asn1Spec, tagSet) - if substrateFun: - return substrateFun(asn1Object, substrate, length) - - namedTypes = asn1Object.getComponentType() - - if not self.orderedComponents or not namedTypes or namedTypes.hasOptionalOrDefault: - seenIndices = set() - idx = 0 - while head: - asn1Spec = self._getComponentTagMap(asn1Object, idx) - component, head = decodeFun(head, asn1Spec) - idx = self._getComponentPositionByType( - asn1Object, component.effectiveTagSet, idx - ) - - asn1Object.setComponentByPosition( - idx, component, - verifyConstraints=False, - matchTags=False, matchConstraints=False - ) - seenIndices.add(idx) - idx += 1 - - if namedTypes and not namedTypes.requiredComponents.issubset(seenIndices): - raise error.PyAsn1Error('ASN.1 object %s has uninitialized components' % asn1Object.__class__.__name__) - else: - for idx, asn1Spec in enumerate(namedTypes.values()): - component, head = decodeFun(head, asn1Spec) - asn1Object.setComponentByPosition( - idx, component, - verifyConstraints=False, - matchTags=False, matchConstraints=False - ) - - if not namedTypes: - asn1Object.verifySizeSpec() - - return asn1Object, tail - - def indefLenValueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): - asn1Object = self._createComponent(asn1Spec, tagSet) - if substrateFun: - return substrateFun(asn1Object, substrate, length) - - namedTypes = asn1Object.getComponentType() - - if not namedTypes or namedTypes.hasOptionalOrDefault: - seenIndices = set() - idx = 0 - while substrate: - asn1Spec = self._getComponentTagMap(asn1Object, idx) - component, substrate = decodeFun(substrate, asn1Spec, allowEoo=True) - if component is eoo.endOfOctets: - break - idx = self._getComponentPositionByType( - asn1Object, component.effectiveTagSet, idx - ) - - asn1Object.setComponentByPosition( - idx, component, - verifyConstraints=False, - matchTags=False, matchConstraints=False - ) - seenIndices.add(idx) - idx += 1 - - else: - raise error.SubstrateUnderrunError( - 'No EOO seen before substrate ends' - ) - - if namedTypes and not namedTypes.requiredComponents.issubset(seenIndices): - raise error.PyAsn1Error('ASN.1 object %s has uninitialized components' % asn1Object.__class__.__name__) - else: - for idx, asn1Spec in enumerate(namedTypes.values()): - component, substrate = decodeFun(substrate, asn1Spec) - - asn1Object.setComponentByPosition( - idx, component, - verifyConstraints=False, - matchTags=False, matchConstraints=False - ) - - component, substrate = decodeFun(substrate, eoo.endOfOctets, allowEoo=True) - if component is not eoo.endOfOctets: - raise error.SubstrateUnderrunError( - 'No EOO seen before substrate ends' - ) - - if not namedTypes: - asn1Object.verifySizeSpec() - - return asn1Object, substrate - -class SequenceDecoder(SequenceAndSetDecoderBase): - protoComponent = univ.Sequence() - orderedComponents = True - - def _getComponentTagMap(self, asn1Object, idx): - try: - return asn1Object.getComponentTagMapNearPosition(idx) - except error.PyAsn1Error: - return - - def _getComponentPositionByType(self, asn1Object, tagSet, idx): - return asn1Object.getComponentPositionNearType(tagSet, idx) - - -class SequenceOfDecoder(AbstractConstructedDecoder): - protoComponent = univ.SequenceOf() - - def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): - head, tail = substrate[:length], substrate[length:] - asn1Object = self._createComponent(asn1Spec, tagSet) - if substrateFun: - return substrateFun(asn1Object, substrate, length) - asn1Spec = asn1Object.getComponentType() - idx = 0 - while head: - component, head = decodeFun(head, asn1Spec) - asn1Object.setComponentByPosition( - idx, component, - verifyConstraints=False, - matchTags=False, matchConstraints=False - ) - idx += 1 - asn1Object.verifySizeSpec() - return asn1Object, tail - - def indefLenValueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): - asn1Object = self._createComponent(asn1Spec, tagSet) - if substrateFun: - return substrateFun(asn1Object, substrate, length) - asn1Spec = asn1Object.getComponentType() - idx = 0 - while substrate: - component, substrate = decodeFun(substrate, asn1Spec, allowEoo=True) - if component is eoo.endOfOctets: - break - asn1Object.setComponentByPosition( - idx, component, - verifyConstraints=False, - matchTags=False, matchConstraints=False - ) - idx += 1 - else: - raise error.SubstrateUnderrunError( - 'No EOO seen before substrate ends' - ) - asn1Object.verifySizeSpec() - return asn1Object, substrate - - -class SetDecoder(SequenceAndSetDecoderBase): - protoComponent = univ.Set() - orderedComponents = False - - def _getComponentTagMap(self, asn1Object, idx): - return asn1Object.componentTagMap - - def _getComponentPositionByType(self, asn1Object, tagSet, idx): - nextIdx = asn1Object.getComponentPositionByType(tagSet) - if nextIdx is None: - return idx - else: - return nextIdx - - -class SetOfDecoder(SequenceOfDecoder): - protoComponent = univ.SetOf() - - -class ChoiceDecoder(AbstractConstructedDecoder): - protoComponent = univ.Choice() - tagFormats = (tag.tagFormatSimple, tag.tagFormatConstructed) - - def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): - head, tail = substrate[:length], substrate[length:] - asn1Object = self._createComponent(asn1Spec, tagSet) - if substrateFun: - return substrateFun(asn1Object, substrate, length) - if asn1Object.tagSet == tagSet: # explicitly tagged Choice - component, head = decodeFun( - head, asn1Object.componentTagMap - ) - else: - component, head = decodeFun( - head, asn1Object.componentTagMap, tagSet, length, state - ) - effectiveTagSet = component.effectiveTagSet - asn1Object.setComponentByType( - effectiveTagSet, component, - verifyConstraints=False, - matchTags=False, matchConstraints=False, - innerFlag=False - ) - return asn1Object, tail - - def indefLenValueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): - asn1Object = self._createComponent(asn1Spec, tagSet) - if substrateFun: - return substrateFun(asn1Object, substrate, length) - if asn1Object.tagSet == tagSet: # explicitly tagged Choice - component, substrate = decodeFun(substrate, asn1Object.componentTagMap) - # eat up EOO marker - eooMarker, substrate = decodeFun(substrate, allowEoo=True) - if eooMarker is not eoo.endOfOctets: - raise error.PyAsn1Error('No EOO seen before substrate ends') - else: - component, substrate = decodeFun( - substrate, asn1Object.componentTagMap, tagSet, length, state - ) - effectiveTagSet = component.effectiveTagSet - asn1Object.setComponentByType( - effectiveTagSet, component, - verifyConstraints=False, - matchTags=False, matchConstraints=False, - innerFlag=False - ) - return asn1Object, substrate - - -class AnyDecoder(AbstractSimpleDecoder): - protoComponent = univ.Any() - tagFormats = (tag.tagFormatSimple, tag.tagFormatConstructed) - - def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): - if asn1Spec is None or asn1Spec is not None and tagSet != asn1Spec.tagSet: - # untagged Any container, recover inner header substrate - length += len(fullSubstrate) - len(substrate) - substrate = fullSubstrate - if substrateFun: - return substrateFun(self._createComponent(asn1Spec, tagSet), - substrate, length) - head, tail = substrate[:length], substrate[length:] - return self._createComponent(asn1Spec, tagSet, value=head), tail - - def indefLenValueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): - if asn1Spec is not None and tagSet == asn1Spec.tagSet: - # tagged Any type -- consume header substrate - header = null - else: - # untagged Any, recover header substrate - header = fullSubstrate[:-len(substrate)] - - # Any components do not inherit initial tag - asn1Spec = self.protoComponent - - if substrateFun and substrateFun is not self.substrateCollector: - asn1Object = self._createComponent(asn1Spec, tagSet) - return substrateFun(asn1Object, header + substrate, length + len(header)) - - # All inner fragments are of the same type, treat them as octet string - substrateFun = self.substrateCollector - - while substrate: - component, substrate = decodeFun(substrate, asn1Spec, - substrateFun=substrateFun, - allowEoo=True) - if component is eoo.endOfOctets: - break - header += component - else: - raise error.SubstrateUnderrunError( - 'No EOO seen before substrate ends' - ) - if substrateFun: - return header, substrate - else: - return self._createComponent(asn1Spec, tagSet, header), substrate - - -# character string types -class UTF8StringDecoder(OctetStringDecoder): - protoComponent = char.UTF8String() - - -class NumericStringDecoder(OctetStringDecoder): - protoComponent = char.NumericString() - - -class PrintableStringDecoder(OctetStringDecoder): - protoComponent = char.PrintableString() - - -class TeletexStringDecoder(OctetStringDecoder): - protoComponent = char.TeletexString() - - -class VideotexStringDecoder(OctetStringDecoder): - protoComponent = char.VideotexString() - - -class IA5StringDecoder(OctetStringDecoder): - protoComponent = char.IA5String() - - -class GraphicStringDecoder(OctetStringDecoder): - protoComponent = char.GraphicString() - - -class VisibleStringDecoder(OctetStringDecoder): - protoComponent = char.VisibleString() - - -class GeneralStringDecoder(OctetStringDecoder): - protoComponent = char.GeneralString() - - -class UniversalStringDecoder(OctetStringDecoder): - protoComponent = char.UniversalString() - - -class BMPStringDecoder(OctetStringDecoder): - protoComponent = char.BMPString() - - -# "useful" types -class ObjectDescriptorDecoder(OctetStringDecoder): - protoComponent = useful.ObjectDescriptor() - - -class GeneralizedTimeDecoder(OctetStringDecoder): - protoComponent = useful.GeneralizedTime() - - -class UTCTimeDecoder(OctetStringDecoder): - protoComponent = useful.UTCTime() - - -tagMap = { - univ.Integer.tagSet: IntegerDecoder(), - univ.Boolean.tagSet: BooleanDecoder(), - univ.BitString.tagSet: BitStringDecoder(), - univ.OctetString.tagSet: OctetStringDecoder(), - univ.Null.tagSet: NullDecoder(), - univ.ObjectIdentifier.tagSet: ObjectIdentifierDecoder(), - univ.Enumerated.tagSet: IntegerDecoder(), - univ.Real.tagSet: RealDecoder(), - univ.Sequence.tagSet: SequenceDecoder(), # conflicts with SequenceOf - univ.Set.tagSet: SetDecoder(), # conflicts with SetOf - univ.Choice.tagSet: ChoiceDecoder(), # conflicts with Any - # character string types - char.UTF8String.tagSet: UTF8StringDecoder(), - char.NumericString.tagSet: NumericStringDecoder(), - char.PrintableString.tagSet: PrintableStringDecoder(), - char.TeletexString.tagSet: TeletexStringDecoder(), - char.VideotexString.tagSet: VideotexStringDecoder(), - char.IA5String.tagSet: IA5StringDecoder(), - char.GraphicString.tagSet: GraphicStringDecoder(), - char.VisibleString.tagSet: VisibleStringDecoder(), - char.GeneralString.tagSet: GeneralStringDecoder(), - char.UniversalString.tagSet: UniversalStringDecoder(), - char.BMPString.tagSet: BMPStringDecoder(), - # useful types - useful.ObjectDescriptor.tagSet: ObjectDescriptorDecoder(), - useful.GeneralizedTime.tagSet: GeneralizedTimeDecoder(), - useful.UTCTime.tagSet: UTCTimeDecoder() -} - -# Type-to-codec map for ambiguous ASN.1 types -typeMap = { - univ.Set.typeId: SetDecoder(), - univ.SetOf.typeId: SetOfDecoder(), - univ.Sequence.typeId: SequenceDecoder(), - univ.SequenceOf.typeId: SequenceOfDecoder(), - univ.Choice.typeId: ChoiceDecoder(), - univ.Any.typeId: AnyDecoder() -} - -# Put in non-ambiguous types for faster codec lookup -for typeDecoder in tagMap.values(): - typeId = typeDecoder.protoComponent.__class__.typeId - if typeId is not None and typeId not in typeMap: - typeMap[typeId] = typeDecoder - - -(stDecodeTag, stDecodeLength, stGetValueDecoder, stGetValueDecoderByAsn1Spec, - stGetValueDecoderByTag, stTryAsExplicitTag, stDecodeValue, - stDumpRawValue, stErrorCondition, stStop) = [x for x in range(10)] - - -class Decoder(object): - defaultErrorState = stErrorCondition - # defaultErrorState = stDumpRawValue - defaultRawDecoder = AnyDecoder() - supportIndefLength = True - - # noinspection PyDefaultArgument - def __init__(self, tagMap, typeMap={}): - self.__tagMap = tagMap - self.__typeMap = typeMap - # Tag & TagSet objects caches - self.__tagCache = {} - self.__tagSetCache = {} - self.__eooSentinel = ints2octs((0, 0)) - - def __call__(self, substrate, asn1Spec=None, tagSet=None, - length=None, state=stDecodeTag, recursiveFlag=True, - substrateFun=None, allowEoo=False): - if debug.logger and debug.logger & debug.flagDecoder: - debug.logger('decoder called at scope %s with state %d, working with up to %d octets of substrate: %s' % (debug.scope, state, len(substrate), debug.hexdump(substrate))) - - substrate = ensureString(substrate) - - # Look for end-of-octets sentinel - if allowEoo and self.supportIndefLength: - if substrate.startswith(self.__eooSentinel): - debug.logger and debug.logger & debug.flagDecoder and debug.logger('end-of-octets sentinel found') - return eoo.endOfOctets, substrate[2:] - - value = base.noValue - - fullSubstrate = substrate - while state != stStop: - if state == stDecodeTag: - if not substrate: - raise error.SubstrateUnderrunError( - 'Short octet stream on tag decoding' - ) - # Decode tag - isShortTag = True - firstOctet = substrate[0] - substrate = substrate[1:] - try: - lastTag = self.__tagCache[firstOctet] - except KeyError: - integerTag = oct2int(firstOctet) - tagClass = integerTag & 0xC0 - tagFormat = integerTag & 0x20 - tagId = integerTag & 0x1F - if tagId == 0x1F: - isShortTag = False - lengthOctetIdx = 0 - tagId = 0 - try: - while True: - integerTag = oct2int(substrate[lengthOctetIdx]) - lengthOctetIdx += 1 - tagId <<= 7 - tagId |= (integerTag & 0x7F) - if not integerTag & 0x80: - break - substrate = substrate[lengthOctetIdx:] - except IndexError: - raise error.SubstrateUnderrunError( - 'Short octet stream on long tag decoding' - ) - lastTag = tag.Tag( - tagClass=tagClass, tagFormat=tagFormat, tagId=tagId - ) - if isShortTag: - # cache short tags - self.__tagCache[firstOctet] = lastTag - if tagSet is None: - if isShortTag: - try: - tagSet = self.__tagSetCache[firstOctet] - except KeyError: - # base tag not recovered - tagSet = tag.TagSet((), lastTag) - self.__tagSetCache[firstOctet] = tagSet - else: - tagSet = tag.TagSet((), lastTag) - else: - tagSet = lastTag + tagSet - state = stDecodeLength - debug.logger and debug.logger & debug.flagDecoder and debug.logger( - 'tag decoded into %s, decoding length' % tagSet) - if state == stDecodeLength: - # Decode length - if not substrate: - raise error.SubstrateUnderrunError( - 'Short octet stream on length decoding' - ) - firstOctet = oct2int(substrate[0]) - if firstOctet < 128: - size = 1 - length = firstOctet - elif firstOctet == 128: - size = 1 - length = -1 - else: - size = firstOctet & 0x7F - # encoded in size bytes - encodedLength = octs2ints(substrate[1:size + 1]) - # missing check on maximum size, which shouldn't be a - # problem, we can handle more than is possible - if len(encodedLength) != size: - raise error.SubstrateUnderrunError( - '%s<%s at %s' % (size, len(encodedLength), tagSet) - ) - length = 0 - for lengthOctet in encodedLength: - length <<= 8 - length |= lengthOctet - size += 1 - substrate = substrate[size:] - if length == -1: - if not self.supportIndefLength: - raise error.PyAsn1Error('Indefinite length encoding not supported by this codec') - else: - if len(substrate) < length: - raise error.SubstrateUnderrunError('%d-octet short' % (length - len(substrate))) - state = stGetValueDecoder - debug.logger and debug.logger & debug.flagDecoder and debug.logger( - 'value length decoded into %d, payload substrate is: %s' % (length, debug.hexdump(length == -1 and substrate or substrate[:length])) - ) - if state == stGetValueDecoder: - if asn1Spec is None: - state = stGetValueDecoderByTag - else: - state = stGetValueDecoderByAsn1Spec - # - # There're two ways of creating subtypes in ASN.1 what influences - # decoder operation. These methods are: - # 1) Either base types used in or no IMPLICIT tagging has been - # applied on subtyping. - # 2) Subtype syntax drops base type information (by means of - # IMPLICIT tagging. - # The first case allows for complete tag recovery from substrate - # while the second one requires original ASN.1 type spec for - # decoding. - # - # In either case a set of tags (tagSet) is coming from substrate - # in an incremental, tag-by-tag fashion (this is the case of - # EXPLICIT tag which is most basic). Outermost tag comes first - # from the wire. - # - if state == stGetValueDecoderByTag: - try: - concreteDecoder = self.__tagMap[tagSet] - except KeyError: - concreteDecoder = None - if concreteDecoder: - state = stDecodeValue - else: - try: - concreteDecoder = self.__tagMap[tagSet[:1]] - except KeyError: - concreteDecoder = None - if concreteDecoder: - state = stDecodeValue - else: - state = stTryAsExplicitTag - if debug.logger and debug.logger & debug.flagDecoder: - debug.logger('codec %s chosen by a built-in type, decoding %s' % (concreteDecoder and concreteDecoder.__class__.__name__ or "", state == stDecodeValue and 'value' or 'as explicit tag')) - debug.scope.push( - concreteDecoder is None and '?' or concreteDecoder.protoComponent.__class__.__name__) - if state == stGetValueDecoderByAsn1Spec: - if asn1Spec.__class__ is dict or asn1Spec.__class__ is tagmap.TagMap: - try: - chosenSpec = asn1Spec[tagSet] - except KeyError: - chosenSpec = None - if debug.logger and debug.logger & debug.flagDecoder: - debug.logger('candidate ASN.1 spec is a map of:') - for firstOctet, v in asn1Spec.presentTypes.items(): - debug.logger(' %s -> %s' % (firstOctet, v.__class__.__name__)) - if asn1Spec.skipTypes: - debug.logger('but neither of: ') - for firstOctet, v in asn1Spec.skipTypes.items(): - debug.logger(' %s -> %s' % (firstOctet, v.__class__.__name__)) - debug.logger('new candidate ASN.1 spec is %s, chosen by %s' % (chosenSpec is None and '' or chosenSpec.prettyPrintType(), tagSet)) - else: - if tagSet == asn1Spec.tagSet or tagSet in asn1Spec.tagMap: - chosenSpec = asn1Spec - debug.logger and debug.logger & debug.flagDecoder and debug.logger( - 'candidate ASN.1 spec is %s' % asn1Spec.__class__.__name__) - else: - chosenSpec = None - - if chosenSpec is not None: - try: - # ambiguous type or just faster codec lookup - concreteDecoder = self.__typeMap[chosenSpec.typeId] - debug.logger and debug.logger & debug.flagDecoder and debug.logger( - 'value decoder chosen for an ambiguous type by type ID %s' % (chosenSpec.typeId,)) - except KeyError: - # use base type for codec lookup to recover untagged types - baseTagSet = tag.TagSet(chosenSpec.tagSet.baseTag, chosenSpec.tagSet.baseTag) - try: - # base type or tagged subtype - concreteDecoder = self.__tagMap[baseTagSet] - debug.logger and debug.logger & debug.flagDecoder and debug.logger( - 'value decoder chosen by base %s' % (baseTagSet,)) - except KeyError: - concreteDecoder = None - if concreteDecoder: - asn1Spec = chosenSpec - state = stDecodeValue - else: - state = stTryAsExplicitTag - else: - concreteDecoder = None - state = stTryAsExplicitTag - if debug.logger and debug.logger & debug.flagDecoder: - debug.logger('codec %s chosen by ASN.1 spec, decoding %s' % (state == stDecodeValue and concreteDecoder.__class__.__name__ or "", state == stDecodeValue and 'value' or 'as explicit tag')) - debug.scope.push(chosenSpec is None and '?' or chosenSpec.__class__.__name__) - if state == stTryAsExplicitTag: - if tagSet and tagSet[0].tagFormat == tag.tagFormatConstructed and tagSet[0].tagClass != tag.tagClassUniversal: - # Assume explicit tagging - concreteDecoder = explicitTagDecoder - state = stDecodeValue - else: - concreteDecoder = None - state = self.defaultErrorState - debug.logger and debug.logger & debug.flagDecoder and debug.logger('codec %s chosen, decoding %s' % (concreteDecoder and concreteDecoder.__class__.__name__ or "", state == stDecodeValue and 'value' or 'as failure')) - if state == stDumpRawValue: - concreteDecoder = self.defaultRawDecoder - debug.logger and debug.logger & debug.flagDecoder and debug.logger( - 'codec %s chosen, decoding value' % concreteDecoder.__class__.__name__) - state = stDecodeValue - if state == stDecodeValue: - if not recursiveFlag and not substrateFun: # legacy - def substrateFun(a, b, c): - return a, b[:c] - if length == -1: # indef length - value, substrate = concreteDecoder.indefLenValueDecoder( - fullSubstrate, substrate, asn1Spec, tagSet, length, - stGetValueDecoder, self, substrateFun - ) - else: - value, substrate = concreteDecoder.valueDecoder( - fullSubstrate, substrate, asn1Spec, tagSet, length, - stGetValueDecoder, self, substrateFun - ) - state = stStop - debug.logger and debug.logger & debug.flagDecoder and debug.logger( - 'codec %s yields type %s, value:\n%s\n...remaining substrate is: %s' % (concreteDecoder.__class__.__name__, value.__class__.__name__, value.prettyPrint(), substrate and debug.hexdump(substrate) or '')) - if state == stErrorCondition: - raise error.PyAsn1Error( - '%s not in asn1Spec: %s' % (tagSet, asn1Spec) - ) - if debug.logger and debug.logger & debug.flagDecoder: - debug.scope.pop() - debug.logger('decoder left scope %s, call completed' % debug.scope) - return value, substrate - - -#: Turns BER octet stream into an ASN.1 object. -#: -#: Takes BER octetstream and decode it into an ASN.1 object -#: (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) which -#: may be a scalar or an arbitrary nested structure. -#: -#: Parameters -#: ---------- -#: substrate: :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2) -#: BER octetstream -#: -#: asn1Spec: any pyasn1 type object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative -#: A pyasn1 type object to act as a template guiding the decoder. Depending on the ASN.1 structure -#: being decoded, *asn1Spec* may or may not be required. Most common reason for -#: it to require is that ASN.1 structure is encoded in *IMPLICIT* tagging mode. -#: -#: Returns -#: ------- -#: : :py:class:`tuple` -#: A tuple of pyasn1 object recovered from BER substrate (:py:class:`~pyasn1.type.base.PyAsn1Item` derivative) -#: and the unprocessed trailing portion of the *substrate* (may be empty) -#: -#: Raises -#: ------ -#: : :py:class:`pyasn1.error.PyAsn1Error` -#: On decoding errors -decode = Decoder(tagMap, typeMap) - -# XXX -# non-recursive decoding; return position rather than substrate diff --git a/src/lib/pyasn1/codec/ber/encoder.py b/src/lib/pyasn1/codec/ber/encoder.py deleted file mode 100644 index 2bf2bc7f..00000000 --- a/src/lib/pyasn1/codec/ber/encoder.py +++ /dev/null @@ -1,506 +0,0 @@ -# -# This file is part of pyasn1 software. -# -# Copyright (c) 2005-2017, Ilya Etingof -# License: http://pyasn1.sf.net/license.html -# -from pyasn1.type import base, tag, univ, char, useful -from pyasn1.codec.ber import eoo -from pyasn1.compat.octets import int2oct, oct2int, ints2octs, null, str2octs -from pyasn1.compat.integer import to_bytes -from pyasn1 import debug, error - -__all__ = ['encode'] - - -class AbstractItemEncoder(object): - supportIndefLenMode = 1 - - # noinspection PyMethodMayBeStatic - def encodeTag(self, singleTag, isConstructed): - tagClass, tagFormat, tagId = singleTag - encodedTag = tagClass | tagFormat - if isConstructed: - encodedTag |= tag.tagFormatConstructed - if tagId < 31: - return (encodedTag | tagId,) - else: - substrate = (tagId & 0x7f,) - tagId >>= 7 - while tagId: - substrate = (0x80 | (tagId & 0x7f),) + substrate - tagId >>= 7 - return (encodedTag | 0x1F,) + substrate - - def encodeLength(self, length, defMode): - if not defMode and self.supportIndefLenMode: - return (0x80,) - if length < 0x80: - return (length,) - else: - substrate = () - while length: - substrate = (length & 0xff,) + substrate - length >>= 8 - substrateLen = len(substrate) - if substrateLen > 126: - raise error.PyAsn1Error('Length octets overflow (%d)' % substrateLen) - return (0x80 | substrateLen,) + substrate - - def encodeValue(self, encodeFun, value, defMode, maxChunkSize): - raise error.PyAsn1Error('Not implemented') - - def _encodeEndOfOctets(self, encodeFun, defMode): - if defMode or not self.supportIndefLenMode: - return null - else: - return encodeFun(eoo.endOfOctets, defMode) - - def encode(self, encodeFun, value, defMode, maxChunkSize): - substrate, isConstructed, isOctets = self.encodeValue( - encodeFun, value, defMode, maxChunkSize - ) - tagSet = value.tagSet - # tagged value? - if tagSet: - if not isConstructed: # primitive form implies definite mode - defMode = True - header = self.encodeTag(tagSet[-1], isConstructed) - header += self.encodeLength(len(substrate), defMode) - - if isOctets: - substrate = ints2octs(header) + substrate - else: - substrate = ints2octs(header + substrate) - - eoo = self._encodeEndOfOctets(encodeFun, defMode) - if eoo: - substrate += eoo - - return substrate - - -class EndOfOctetsEncoder(AbstractItemEncoder): - def encodeValue(self, encodeFun, value, defMode, maxChunkSize): - return null, False, True - - -class ExplicitlyTaggedItemEncoder(AbstractItemEncoder): - def encodeValue(self, encodeFun, value, defMode, maxChunkSize): - if isinstance(value, base.AbstractConstructedAsn1Item): - value = value.clone(tagSet=value.tagSet[:-1], cloneValueFlag=1) - else: - value = value.clone(tagSet=value.tagSet[:-1]) - return encodeFun(value, defMode, maxChunkSize), True, True - - -explicitlyTaggedItemEncoder = ExplicitlyTaggedItemEncoder() - - -class BooleanEncoder(AbstractItemEncoder): - supportIndefLenMode = False - - def encodeValue(self, encodeFun, value, defMode, maxChunkSize): - return value and (1,) or (0,), False, False - - -class IntegerEncoder(AbstractItemEncoder): - supportIndefLenMode = False - supportCompactZero = False - - def encodeValue(self, encodeFun, value, defMode, maxChunkSize): - if value == 0: - # de-facto way to encode zero - if self.supportCompactZero: - return (), False, False - else: - return (0,), False, False - - return to_bytes(int(value), signed=True), False, True - - -class BitStringEncoder(AbstractItemEncoder): - def encodeValue(self, encodeFun, value, defMode, maxChunkSize): - valueLength = len(value) - if valueLength % 8: - alignedValue = value << (8 - valueLength % 8) - else: - alignedValue = value - - if not maxChunkSize or len(alignedValue) <= maxChunkSize * 8: - substrate = alignedValue.asOctets() - return int2oct(len(substrate) * 8 - valueLength) + substrate, False, True - - stop = 0 - substrate = null - while stop < valueLength: - start = stop - stop = min(start + maxChunkSize * 8, valueLength) - substrate += encodeFun(alignedValue[start:stop], defMode, maxChunkSize) - - return substrate, True, True - - -class OctetStringEncoder(AbstractItemEncoder): - def encodeValue(self, encodeFun, value, defMode, maxChunkSize): - if not maxChunkSize or len(value) <= maxChunkSize: - return value.asOctets(), False, True - else: - pos = 0 - substrate = null - while True: - v = value.clone(value[pos:pos + maxChunkSize]) - if not v: - break - substrate += encodeFun(v, defMode, maxChunkSize) - pos += maxChunkSize - - return substrate, True, True - - -class NullEncoder(AbstractItemEncoder): - supportIndefLenMode = False - - def encodeValue(self, encodeFun, value, defMode, maxChunkSize): - return null, False, True - - -class ObjectIdentifierEncoder(AbstractItemEncoder): - supportIndefLenMode = False - - def encodeValue(self, encodeFun, value, defMode, maxChunkSize): - oid = value.asTuple() - - # Build the first pair - try: - first = oid[0] - second = oid[1] - - except IndexError: - raise error.PyAsn1Error('Short OID %s' % (value,)) - - if 0 <= second <= 39: - if first == 1: - oid = (second + 40,) + oid[2:] - elif first == 0: - oid = (second,) + oid[2:] - elif first == 2: - oid = (second + 80,) + oid[2:] - else: - raise error.PyAsn1Error('Impossible first/second arcs at %s' % (value,)) - elif first == 2: - oid = (second + 80,) + oid[2:] - else: - raise error.PyAsn1Error('Impossible first/second arcs at %s' % (value,)) - - octets = () - - # Cycle through subIds - for subOid in oid: - if 0 <= subOid <= 127: - # Optimize for the common case - octets += (subOid,) - elif subOid > 127: - # Pack large Sub-Object IDs - res = (subOid & 0x7f,) - subOid >>= 7 - while subOid: - res = (0x80 | (subOid & 0x7f),) + res - subOid >>= 7 - # Add packed Sub-Object ID to resulted Object ID - octets += res - else: - raise error.PyAsn1Error('Negative OID arc %s at %s' % (subOid, value)) - - return octets, False, False - - -class RealEncoder(AbstractItemEncoder): - supportIndefLenMode = 0 - binEncBase = 2 # set to None to choose encoding base automatically - - @staticmethod - def _dropFloatingPoint(m, encbase, e): - ms, es = 1, 1 - if m < 0: - ms = -1 # mantissa sign - if e < 0: - es = -1 # exponenta sign - m *= ms - if encbase == 8: - m *= 2 ** (abs(e) % 3 * es) - e = abs(e) // 3 * es - elif encbase == 16: - m *= 2 ** (abs(e) % 4 * es) - e = abs(e) // 4 * es - - while True: - if int(m) != m: - m *= encbase - e -= 1 - continue - break - return ms, int(m), encbase, e - - def _chooseEncBase(self, value): - m, b, e = value - encBase = [2, 8, 16] - if value.binEncBase in encBase: - return self._dropFloatingPoint(m, value.binEncBase, e) - elif self.binEncBase in encBase: - return self._dropFloatingPoint(m, self.binEncBase, e) - # auto choosing base 2/8/16 - mantissa = [m, m, m] - exponenta = [e, e, e] - sign = 1 - encbase = 2 - e = float('inf') - for i in range(3): - (sign, - mantissa[i], - encBase[i], - exponenta[i]) = self._dropFloatingPoint(mantissa[i], encBase[i], exponenta[i]) - if abs(exponenta[i]) < abs(e) or (abs(exponenta[i]) == abs(e) and mantissa[i] < m): - e = exponenta[i] - m = int(mantissa[i]) - encbase = encBase[i] - return sign, m, encbase, e - - def encodeValue(self, encodeFun, value, defMode, maxChunkSize): - if value.isPlusInfinity(): - return (0x40,), False, False - if value.isMinusInfinity(): - return (0x41,), False, False - m, b, e = value - if not m: - return null, False, True - if b == 10: - return str2octs('\x03%dE%s%d' % (m, e == 0 and '+' or '', e)), False, True - elif b == 2: - fo = 0x80 # binary encoding - ms, m, encbase, e = self._chooseEncBase(value) - if ms < 0: # mantissa sign - fo |= 0x40 # sign bit - # exponenta & mantissa normalization - if encbase == 2: - while m & 0x1 == 0: - m >>= 1 - e += 1 - elif encbase == 8: - while m & 0x7 == 0: - m >>= 3 - e += 1 - fo |= 0x10 - else: # encbase = 16 - while m & 0xf == 0: - m >>= 4 - e += 1 - fo |= 0x20 - sf = 0 # scale factor - while m & 0x1 == 0: - m >>= 1 - sf += 1 - if sf > 3: - raise error.PyAsn1Error('Scale factor overflow') # bug if raised - fo |= sf << 2 - eo = null - if e == 0 or e == -1: - eo = int2oct(e & 0xff) - else: - while e not in (0, -1): - eo = int2oct(e & 0xff) + eo - e >>= 8 - if e == 0 and eo and oct2int(eo[0]) & 0x80: - eo = int2oct(0) + eo - if e == -1 and eo and not (oct2int(eo[0]) & 0x80): - eo = int2oct(0xff) + eo - n = len(eo) - if n > 0xff: - raise error.PyAsn1Error('Real exponent overflow') - if n == 1: - pass - elif n == 2: - fo |= 1 - elif n == 3: - fo |= 2 - else: - fo |= 3 - eo = int2oct(n & 0xff) + eo - po = null - while m: - po = int2oct(m & 0xff) + po - m >>= 8 - substrate = int2oct(fo) + eo + po - return substrate, False, True - else: - raise error.PyAsn1Error('Prohibited Real base %s' % b) - - -class SequenceEncoder(AbstractItemEncoder): - def encodeValue(self, encodeFun, value, defMode, maxChunkSize): - value.verifySizeSpec() - namedTypes = value.getComponentType() - substrate = null - idx = len(value) - while idx > 0: - idx -= 1 - if namedTypes: - if namedTypes[idx].isOptional and not value[idx].isValue: - continue - if namedTypes[idx].isDefaulted and value[idx] == namedTypes[idx].asn1Object: - continue - substrate = encodeFun(value[idx], defMode, maxChunkSize) + substrate - return substrate, True, True - - -class SequenceOfEncoder(AbstractItemEncoder): - def encodeValue(self, encodeFun, value, defMode, maxChunkSize): - value.verifySizeSpec() - substrate = null - idx = len(value) - while idx > 0: - idx -= 1 - substrate = encodeFun(value[idx], defMode, maxChunkSize) + substrate - return substrate, True, True - - -class ChoiceEncoder(AbstractItemEncoder): - def encodeValue(self, encodeFun, value, defMode, maxChunkSize): - return encodeFun(value.getComponent(), defMode, maxChunkSize), True, True - - -class AnyEncoder(OctetStringEncoder): - def encodeValue(self, encodeFun, value, defMode, maxChunkSize): - return value.asOctets(), defMode == False, True - - -tagMap = { - eoo.endOfOctets.tagSet: EndOfOctetsEncoder(), - univ.Boolean.tagSet: BooleanEncoder(), - univ.Integer.tagSet: IntegerEncoder(), - univ.BitString.tagSet: BitStringEncoder(), - univ.OctetString.tagSet: OctetStringEncoder(), - univ.Null.tagSet: NullEncoder(), - univ.ObjectIdentifier.tagSet: ObjectIdentifierEncoder(), - univ.Enumerated.tagSet: IntegerEncoder(), - univ.Real.tagSet: RealEncoder(), - # Sequence & Set have same tags as SequenceOf & SetOf - univ.SequenceOf.tagSet: SequenceOfEncoder(), - univ.SetOf.tagSet: SequenceOfEncoder(), - univ.Choice.tagSet: ChoiceEncoder(), - # character string types - char.UTF8String.tagSet: OctetStringEncoder(), - char.NumericString.tagSet: OctetStringEncoder(), - char.PrintableString.tagSet: OctetStringEncoder(), - char.TeletexString.tagSet: OctetStringEncoder(), - char.VideotexString.tagSet: OctetStringEncoder(), - char.IA5String.tagSet: OctetStringEncoder(), - char.GraphicString.tagSet: OctetStringEncoder(), - char.VisibleString.tagSet: OctetStringEncoder(), - char.GeneralString.tagSet: OctetStringEncoder(), - char.UniversalString.tagSet: OctetStringEncoder(), - char.BMPString.tagSet: OctetStringEncoder(), - # useful types - useful.ObjectDescriptor.tagSet: OctetStringEncoder(), - useful.GeneralizedTime.tagSet: OctetStringEncoder(), - useful.UTCTime.tagSet: OctetStringEncoder() -} - -# Put in ambiguous & non-ambiguous types for faster codec lookup -typeMap = { - univ.Boolean.typeId: BooleanEncoder(), - univ.Integer.typeId: IntegerEncoder(), - univ.BitString.typeId: BitStringEncoder(), - univ.OctetString.typeId: OctetStringEncoder(), - univ.Null.typeId: NullEncoder(), - univ.ObjectIdentifier.typeId: ObjectIdentifierEncoder(), - univ.Enumerated.typeId: IntegerEncoder(), - univ.Real.typeId: RealEncoder(), - # Sequence & Set have same tags as SequenceOf & SetOf - univ.Set.typeId: SequenceEncoder(), - univ.SetOf.typeId: SequenceOfEncoder(), - univ.Sequence.typeId: SequenceEncoder(), - univ.SequenceOf.typeId: SequenceOfEncoder(), - univ.Choice.typeId: ChoiceEncoder(), - univ.Any.typeId: AnyEncoder(), - # character string types - char.UTF8String.typeId: OctetStringEncoder(), - char.NumericString.typeId: OctetStringEncoder(), - char.PrintableString.typeId: OctetStringEncoder(), - char.TeletexString.typeId: OctetStringEncoder(), - char.VideotexString.typeId: OctetStringEncoder(), - char.IA5String.typeId: OctetStringEncoder(), - char.GraphicString.typeId: OctetStringEncoder(), - char.VisibleString.typeId: OctetStringEncoder(), - char.GeneralString.typeId: OctetStringEncoder(), - char.UniversalString.typeId: OctetStringEncoder(), - char.BMPString.typeId: OctetStringEncoder(), - # useful types - useful.ObjectDescriptor.typeId: OctetStringEncoder(), - useful.GeneralizedTime.typeId: OctetStringEncoder(), - useful.UTCTime.typeId: OctetStringEncoder() -} - - -class Encoder(object): - supportIndefLength = True - - # noinspection PyDefaultArgument - def __init__(self, tagMap, typeMap={}): - self.__tagMap = tagMap - self.__typeMap = typeMap - - def __call__(self, value, defMode=True, maxChunkSize=0): - if not defMode and not self.supportIndefLength: - raise error.PyAsn1Error('Indefinite length encoding not supported by this codec') - debug.logger & debug.flagEncoder and debug.logger( - 'encoder called in %sdef mode, chunk size %s for type %s, value:\n%s' % ( - not defMode and 'in' or '', maxChunkSize, value.prettyPrintType(), value.prettyPrint())) - tagSet = value.tagSet - if len(tagSet) > 1: - concreteEncoder = explicitlyTaggedItemEncoder - else: - try: - concreteEncoder = self.__typeMap[value.typeId] - except KeyError: - # use base type for codec lookup to recover untagged types - baseTagSet = tag.TagSet(value.tagSet.baseTag, value.tagSet.baseTag) - try: - concreteEncoder = self.__tagMap[baseTagSet] - except KeyError: - raise error.PyAsn1Error('No encoder for %s' % (value,)) - debug.logger & debug.flagEncoder and debug.logger( - 'using value codec %s chosen by %s' % (concreteEncoder.__class__.__name__, tagSet)) - substrate = concreteEncoder.encode( - self, value, defMode, maxChunkSize - ) - debug.logger & debug.flagEncoder and debug.logger( - 'built %s octets of substrate: %s\nencoder completed' % (len(substrate), debug.hexdump(substrate))) - return substrate - -#: Turns ASN.1 object into BER octet stream. -#: -#: Takes any ASN.1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) -#: walks all its components recursively and produces a BER octet stream. -#: -#: Parameters -#: ---------- -# value: any pyasn1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) -#: A pyasn1 object to encode -#: -#: defMode: :py:class:`bool` -#: If `False`, produces indefinite length encoding -#: -#: maxChunkSize: :py:class:`int` -#: Maximum chunk size in chunked encoding mode (0 denotes unlimited chunk size) -#: -#: Returns -#: ------- -#: : :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2) -#: Given ASN.1 object encoded into BER octetstream -#: -#: Raises -#: ------ -#: : :py:class:`pyasn1.error.PyAsn1Error` -#: On encoding errors -encode = Encoder(tagMap, typeMap) diff --git a/src/lib/pyasn1/codec/ber/eoo.py b/src/lib/pyasn1/codec/ber/eoo.py deleted file mode 100644 index b02f5cc4..00000000 --- a/src/lib/pyasn1/codec/ber/eoo.py +++ /dev/null @@ -1,25 +0,0 @@ -# -# This file is part of pyasn1 software. -# -# Copyright (c) 2005-2017, Ilya Etingof -# License: http://pyasn1.sf.net/license.html -# -from pyasn1.type import base, tag - - -class EndOfOctets(base.AbstractSimpleAsn1Item): - defaultValue = 0 - tagSet = tag.initTagSet( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x00) - ) - - _instance = None - - def __new__(cls, *args): - if cls._instance is None: - cls._instance = object.__new__(cls, *args) - - return cls._instance - - -endOfOctets = EndOfOctets() diff --git a/src/lib/pyasn1/codec/cer/__init__.py b/src/lib/pyasn1/codec/cer/__init__.py deleted file mode 100644 index 8c3066b2..00000000 --- a/src/lib/pyasn1/codec/cer/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# This file is necessary to make this directory a package. diff --git a/src/lib/pyasn1/codec/cer/decoder.py b/src/lib/pyasn1/codec/cer/decoder.py deleted file mode 100644 index bf9cf4af..00000000 --- a/src/lib/pyasn1/codec/cer/decoder.py +++ /dev/null @@ -1,87 +0,0 @@ -# -# This file is part of pyasn1 software. -# -# Copyright (c) 2005-2017, Ilya Etingof -# License: http://pyasn1.sf.net/license.html -# -from pyasn1.type import univ -from pyasn1.codec.ber import decoder -from pyasn1.compat.octets import oct2int -from pyasn1 import error - -__all__ = ['decode'] - - -class BooleanDecoder(decoder.AbstractSimpleDecoder): - protoComponent = univ.Boolean(0) - - def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, length, - state, decodeFun, substrateFun): - head, tail = substrate[:length], substrate[length:] - if not head or length != 1: - raise error.PyAsn1Error('Not single-octet Boolean payload') - byte = oct2int(head[0]) - # CER/DER specifies encoding of TRUE as 0xFF and FALSE as 0x0, while - # BER allows any non-zero value as TRUE; cf. sections 8.2.2. and 11.1 - # in http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf - if byte == 0xff: - value = 1 - elif byte == 0x00: - value = 0 - else: - raise error.PyAsn1Error('Unexpected Boolean payload: %s' % byte) - return self._createComponent(asn1Spec, tagSet, value), tail - -# TODO: prohibit non-canonical encoding -BitStringDecoder = decoder.BitStringDecoder -OctetStringDecoder = decoder.OctetStringDecoder -RealDecoder = decoder.RealDecoder - -tagMap = decoder.tagMap.copy() -tagMap.update( - {univ.Boolean.tagSet: BooleanDecoder(), - univ.BitString.tagSet: BitStringDecoder(), - univ.OctetString.tagSet: OctetStringDecoder(), - univ.Real.tagSet: RealDecoder()} -) - -typeMap = decoder.typeMap.copy() - -# Put in non-ambiguous types for faster codec lookup -for typeDecoder in tagMap.values(): - typeId = typeDecoder.protoComponent.__class__.typeId - if typeId is not None and typeId not in typeMap: - typeMap[typeId] = typeDecoder - - -class Decoder(decoder.Decoder): - pass - - -#: Turns CER octet stream into an ASN.1 object. -#: -#: Takes CER octetstream and decode it into an ASN.1 object -#: (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) which -#: may be a scalar or an arbitrary nested structure. -#: -#: Parameters -#: ---------- -#: substrate: :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2) -#: CER octetstream -#: -#: asn1Spec: any pyasn1 type object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative -#: A pyasn1 type object to act as a template guiding the decoder. Depending on the ASN.1 structure -#: being decoded, *asn1Spec* may or may not be required. Most common reason for -#: it to require is that ASN.1 structure is encoded in *IMPLICIT* tagging mode. -#: -#: Returns -#: ------- -#: : :py:class:`tuple` -#: A tuple of pyasn1 object recovered from CER substrate (:py:class:`~pyasn1.type.base.PyAsn1Item` derivative) -#: and the unprocessed trailing portion of the *substrate* (may be empty) -#: -#: Raises -#: ------ -#: : :py:class:`pyasn1.error.PyAsn1Error` -#: On decoding errors -decode = Decoder(tagMap, decoder.typeMap) diff --git a/src/lib/pyasn1/codec/cer/encoder.py b/src/lib/pyasn1/codec/cer/encoder.py deleted file mode 100644 index e241e43d..00000000 --- a/src/lib/pyasn1/codec/cer/encoder.py +++ /dev/null @@ -1,179 +0,0 @@ -# -# This file is part of pyasn1 software. -# -# Copyright (c) 2005-2017, Ilya Etingof -# License: http://pyasn1.sf.net/license.html -# -from pyasn1.type import univ -from pyasn1.type import useful -from pyasn1.codec.ber import encoder -from pyasn1.compat.octets import int2oct, str2octs, null -from pyasn1 import error - -__all__ = ['encode'] - - -class BooleanEncoder(encoder.IntegerEncoder): - def encodeValue(self, encodeFun, client, defMode, maxChunkSize): - if client == 0: - substrate = (0,) - else: - substrate = (255,) - return substrate, False, False - - -class BitStringEncoder(encoder.BitStringEncoder): - def encodeValue(self, encodeFun, client, defMode, maxChunkSize): - return encoder.BitStringEncoder.encodeValue( - self, encodeFun, client, defMode, 1000 - ) - - -class OctetStringEncoder(encoder.OctetStringEncoder): - def encodeValue(self, encodeFun, client, defMode, maxChunkSize): - return encoder.OctetStringEncoder.encodeValue( - self, encodeFun, client, defMode, 1000 - ) - - -class RealEncoder(encoder.RealEncoder): - def _chooseEncBase(self, value): - m, b, e = value - return self._dropFloatingPoint(m, b, e) - - -# specialized GeneralStringEncoder here - -class GeneralizedTimeEncoder(OctetStringEncoder): - zchar = str2octs('Z') - pluschar = str2octs('+') - minuschar = str2octs('-') - zero = str2octs('0') - - def encodeValue(self, encodeFun, client, defMode, maxChunkSize): - octets = client.asOctets() - # This breaks too many existing data items - # if '.' not in octets: - # raise error.PyAsn1Error('Format must include fraction of second: %r' % octets) - if len(octets) < 15: - raise error.PyAsn1Error('Bad UTC time length: %r' % octets) - if self.pluschar in octets or self.minuschar in octets: - raise error.PyAsn1Error('Must be UTC time: %r' % octets) - if octets[-1] != self.zchar[0]: - raise error.PyAsn1Error('Missing timezone specifier: %r' % octets) - return encoder.OctetStringEncoder.encodeValue( - self, encodeFun, client, defMode, 1000 - ) - - -class UTCTimeEncoder(encoder.OctetStringEncoder): - zchar = str2octs('Z') - pluschar = str2octs('+') - minuschar = str2octs('-') - - def encodeValue(self, encodeFun, client, defMode, maxChunkSize): - octets = client.asOctets() - if self.pluschar in octets or self.minuschar in octets: - raise error.PyAsn1Error('Must be UTC time: %r' % octets) - if octets and octets[-1] != self.zchar[0]: - client = client.clone(octets + self.zchar) - if len(client) != 13: - raise error.PyAsn1Error('Bad UTC time length: %r' % client) - return encoder.OctetStringEncoder.encodeValue( - self, encodeFun, client, defMode, 1000 - ) - - -class SetOfEncoder(encoder.SequenceOfEncoder): - def encodeValue(self, encodeFun, client, defMode, maxChunkSize): - client.verifySizeSpec() - substrate = null - idx = len(client) - # This is certainly a hack but how else do I distinguish SetOf - # from Set if they have the same tags&constraints? - if isinstance(client, univ.SequenceAndSetBase): - # Set - namedTypes = client.getComponentType() - comps = [] - while idx > 0: - idx -= 1 - if namedTypes[idx].isOptional and not client[idx].isValue: - continue - if namedTypes[idx].isDefaulted and client[idx] == namedTypes[idx].asn1Object: - continue - comps.append(client[idx]) - comps.sort(key=lambda x: isinstance(x, univ.Choice) and x.getMinTagSet() or x.tagSet) - for c in comps: - substrate += encodeFun(c, defMode, maxChunkSize) - else: - # SetOf - compSubs = [] - while idx > 0: - idx -= 1 - compSubs.append( - encodeFun(client[idx], defMode, maxChunkSize) - ) - compSubs.sort() # perhaps padding's not needed - substrate = null - for compSub in compSubs: - substrate += compSub - return substrate, True, True - - -tagMap = encoder.tagMap.copy() -tagMap.update({ - univ.Boolean.tagSet: BooleanEncoder(), - univ.BitString.tagSet: BitStringEncoder(), - univ.OctetString.tagSet: OctetStringEncoder(), - univ.Real.tagSet: RealEncoder(), - useful.GeneralizedTime.tagSet: GeneralizedTimeEncoder(), - useful.UTCTime.tagSet: UTCTimeEncoder(), - univ.SetOf().tagSet: SetOfEncoder() # conflcts with Set -}) - -typeMap = encoder.typeMap.copy() -typeMap.update({ - univ.Boolean.typeId: BooleanEncoder(), - univ.BitString.typeId: BitStringEncoder(), - univ.OctetString.typeId: OctetStringEncoder(), - univ.Real.typeId: RealEncoder(), - useful.GeneralizedTime.typeId: GeneralizedTimeEncoder(), - useful.UTCTime.typeId: UTCTimeEncoder(), - univ.Set.typeId: SetOfEncoder(), - univ.SetOf.typeId: SetOfEncoder() -}) - - -class Encoder(encoder.Encoder): - def __call__(self, client, defMode=False, maxChunkSize=0): - return encoder.Encoder.__call__(self, client, defMode, maxChunkSize) - - -#: Turns ASN.1 object into CER octet stream. -#: -#: Takes any ASN.1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) -#: walks all its components recursively and produces a CER octet stream. -#: -#: Parameters -#: ---------- -# value: any pyasn1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) -#: A pyasn1 object to encode -#: -#: defMode: :py:class:`bool` -#: If `False`, produces indefinite length encoding -#: -#: maxChunkSize: :py:class:`int` -#: Maximum chunk size in chunked encoding mode (0 denotes unlimited chunk size) -#: -#: Returns -#: ------- -#: : :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2) -#: Given ASN.1 object encoded into BER octetstream -#: -#: Raises -#: ------ -#: : :py:class:`pyasn1.error.PyAsn1Error` -#: On encoding errors -encode = Encoder(tagMap, typeMap) - -# EncoderFactory queries class instance and builds a map of tags -> encoders diff --git a/src/lib/pyasn1/codec/der/__init__.py b/src/lib/pyasn1/codec/der/__init__.py deleted file mode 100644 index 8c3066b2..00000000 --- a/src/lib/pyasn1/codec/der/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# This file is necessary to make this directory a package. diff --git a/src/lib/pyasn1/codec/der/decoder.py b/src/lib/pyasn1/codec/der/decoder.py deleted file mode 100644 index 24d3cbcb..00000000 --- a/src/lib/pyasn1/codec/der/decoder.py +++ /dev/null @@ -1,69 +0,0 @@ -# -# This file is part of pyasn1 software. -# -# Copyright (c) 2005-2017, Ilya Etingof -# License: http://pyasn1.sf.net/license.html -# -from pyasn1.type import univ -from pyasn1.codec.cer import decoder - -__all__ = ['decode'] - - -class BitStringDecoder(decoder.BitStringDecoder): - supportConstructedForm = False - - -class OctetStringDecoder(decoder.OctetStringDecoder): - supportConstructedForm = False - -# TODO: prohibit non-canonical encoding -RealDecoder = decoder.RealDecoder - -tagMap = decoder.tagMap.copy() -tagMap.update( - {univ.BitString.tagSet: BitStringDecoder(), - univ.OctetString.tagSet: OctetStringDecoder(), - univ.Real.tagSet: RealDecoder()} -) - -typeMap = decoder.typeMap.copy() - -# Put in non-ambiguous types for faster codec lookup -for typeDecoder in tagMap.values(): - typeId = typeDecoder.protoComponent.__class__.typeId - if typeId is not None and typeId not in typeMap: - typeMap[typeId] = typeDecoder - - -class Decoder(decoder.Decoder): - supportIndefLength = False - - -#: Turns DER octet stream into an ASN.1 object. -#: -#: Takes DER octetstream and decode it into an ASN.1 object -#: (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) which -#: may be a scalar or an arbitrary nested structure. -#: -#: Parameters -#: ---------- -#: substrate: :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2) -#: DER octetstream -#: -#: asn1Spec: any pyasn1 type object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative -#: A pyasn1 type object to act as a template guiding the decoder. Depending on the ASN.1 structure -#: being decoded, *asn1Spec* may or may not be required. Most common reason for -#: it to require is that ASN.1 structure is encoded in *IMPLICIT* tagging mode. -#: -#: Returns -#: ------- -#: : :py:class:`tuple` -#: A tuple of pyasn1 object recovered from DER substrate (:py:class:`~pyasn1.type.base.PyAsn1Item` derivative) -#: and the unprocessed trailing portion of the *substrate* (may be empty) -#: -#: Raises -#: ------ -#: : :py:class:`pyasn1.error.PyAsn1Error` -#: On decoding errors -decode = Decoder(tagMap, typeMap) diff --git a/src/lib/pyasn1/codec/der/encoder.py b/src/lib/pyasn1/codec/der/encoder.py deleted file mode 100644 index 2d615e3f..00000000 --- a/src/lib/pyasn1/codec/der/encoder.py +++ /dev/null @@ -1,67 +0,0 @@ -# -# This file is part of pyasn1 software. -# -# Copyright (c) 2005-2017, Ilya Etingof -# License: http://pyasn1.sf.net/license.html -# -from pyasn1.type import univ -from pyasn1.codec.cer import encoder -from pyasn1 import error - -__all__ = ['encode'] - - -class SetOfEncoder(encoder.SetOfEncoder): - @staticmethod - def _cmpSetComponents(c1, c2): - tagSet1 = isinstance(c1, univ.Choice) and c1.effectiveTagSet or c1.tagSet - tagSet2 = isinstance(c2, univ.Choice) and c2.effectiveTagSet or c2.tagSet - return cmp(tagSet1, tagSet2) - - -tagMap = encoder.tagMap.copy() -tagMap.update({ - # Overload CER encoders with BER ones (a bit hackerish XXX) - univ.BitString.tagSet: encoder.encoder.BitStringEncoder(), - univ.OctetString.tagSet: encoder.encoder.OctetStringEncoder(), - # Set & SetOf have same tags - univ.SetOf().tagSet: SetOfEncoder() -}) - -typeMap = encoder.typeMap.copy() - - -class Encoder(encoder.Encoder): - supportIndefLength = False - - def __call__(self, client, defMode=True, maxChunkSize=0): - if not defMode or maxChunkSize: - raise error.PyAsn1Error('DER forbids indefinite length mode') - return encoder.Encoder.__call__(self, client, defMode, maxChunkSize) - -#: Turns ASN.1 object into DER octet stream. -#: -#: Takes any ASN.1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) -#: walks all its components recursively and produces a DER octet stream. -#: -#: Parameters -#: ---------- -# value: any pyasn1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) -#: A pyasn1 object to encode -#: -#: defMode: :py:class:`bool` -#: If `False`, produces indefinite length encoding -#: -#: maxChunkSize: :py:class:`int` -#: Maximum chunk size in chunked encoding mode (0 denotes unlimited chunk size) -#: -#: Returns -#: ------- -#: : :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2) -#: Given ASN.1 object encoded into BER octetstream -#: -#: Raises -#: ------ -#: : :py:class:`pyasn1.error.PyAsn1Error` -#: On encoding errors -encode = Encoder(tagMap, typeMap) diff --git a/src/lib/pyasn1/codec/native/__init__.py b/src/lib/pyasn1/codec/native/__init__.py deleted file mode 100644 index 8c3066b2..00000000 --- a/src/lib/pyasn1/codec/native/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# This file is necessary to make this directory a package. diff --git a/src/lib/pyasn1/codec/native/decoder.py b/src/lib/pyasn1/codec/native/decoder.py deleted file mode 100644 index be75cb86..00000000 --- a/src/lib/pyasn1/codec/native/decoder.py +++ /dev/null @@ -1,188 +0,0 @@ -# -# This file is part of pyasn1 software. -# -# Copyright (c) 2005-2017, Ilya Etingof -# License: http://pyasn1.sf.net/license.html -# -from pyasn1.type import base, univ, char, useful, tag -from pyasn1 import debug, error - -__all__ = ['decode'] - - -class AbstractScalarDecoder(object): - def __call__(self, pyObject, asn1Spec, decoderFunc=None): - return asn1Spec.clone(pyObject) - - -class BitStringDecoder(AbstractScalarDecoder): - def __call__(self, pyObject, asn1Spec, decoderFunc=None): - return asn1Spec.clone(univ.BitString.fromBinaryString(pyObject)) - - -class SequenceOrSetDecoder(object): - def __call__(self, pyObject, asn1Spec, decoderFunc): - asn1Value = asn1Spec.clone() - - componentsTypes = asn1Spec.getComponentType() - - for field in asn1Value: - if field in pyObject: - asn1Value[field] = decoderFunc(pyObject[field], componentsTypes[field].asn1Object) - - return asn1Value - - -class SequenceOfOrSetOfDecoder(object): - def __call__(self, pyObject, asn1Spec, decoderFunc): - asn1Value = asn1Spec.clone() - - for pyValue in pyObject: - asn1Value.append(decoderFunc(pyValue, asn1Spec.getComponentType())) - - return asn1Value - - -class ChoiceDecoder(object): - def __call__(self, pyObject, asn1Spec, decoderFunc): - asn1Value = asn1Spec.clone() - - componentsTypes = asn1Spec.getComponentType() - - for field in pyObject: - if field in componentsTypes: - asn1Value[field] = decoderFunc(pyObject[field], componentsTypes[field].asn1Object) - break - - return asn1Value - - -tagMap = { - univ.Integer.tagSet: AbstractScalarDecoder(), - univ.Boolean.tagSet: AbstractScalarDecoder(), - univ.BitString.tagSet: BitStringDecoder(), - univ.OctetString.tagSet: AbstractScalarDecoder(), - univ.Null.tagSet: AbstractScalarDecoder(), - univ.ObjectIdentifier.tagSet: AbstractScalarDecoder(), - univ.Enumerated.tagSet: AbstractScalarDecoder(), - univ.Real.tagSet: AbstractScalarDecoder(), - univ.Sequence.tagSet: SequenceOrSetDecoder(), # conflicts with SequenceOf - univ.Set.tagSet: SequenceOrSetDecoder(), # conflicts with SetOf - univ.Choice.tagSet: ChoiceDecoder(), # conflicts with Any - # character string types - char.UTF8String.tagSet: AbstractScalarDecoder(), - char.NumericString.tagSet: AbstractScalarDecoder(), - char.PrintableString.tagSet: AbstractScalarDecoder(), - char.TeletexString.tagSet: AbstractScalarDecoder(), - char.VideotexString.tagSet: AbstractScalarDecoder(), - char.IA5String.tagSet: AbstractScalarDecoder(), - char.GraphicString.tagSet: AbstractScalarDecoder(), - char.VisibleString.tagSet: AbstractScalarDecoder(), - char.GeneralString.tagSet: AbstractScalarDecoder(), - char.UniversalString.tagSet: AbstractScalarDecoder(), - char.BMPString.tagSet: AbstractScalarDecoder(), - # useful types - useful.ObjectDescriptor.tagSet: AbstractScalarDecoder(), - useful.GeneralizedTime.tagSet: AbstractScalarDecoder(), - useful.UTCTime.tagSet: AbstractScalarDecoder() -} - -# Put in ambiguous & non-ambiguous types for faster codec lookup -typeMap = { - univ.Integer.typeId: AbstractScalarDecoder(), - univ.Boolean.typeId: AbstractScalarDecoder(), - univ.BitString.typeId: BitStringDecoder(), - univ.OctetString.typeId: AbstractScalarDecoder(), - univ.Null.typeId: AbstractScalarDecoder(), - univ.ObjectIdentifier.typeId: AbstractScalarDecoder(), - univ.Enumerated.typeId: AbstractScalarDecoder(), - univ.Real.typeId: AbstractScalarDecoder(), - # ambiguous base types - univ.Set.typeId: SequenceOrSetDecoder(), - univ.SetOf.typeId: SequenceOfOrSetOfDecoder(), - univ.Sequence.typeId: SequenceOrSetDecoder(), - univ.SequenceOf.typeId: SequenceOfOrSetOfDecoder(), - univ.Choice.typeId: ChoiceDecoder(), - univ.Any.typeId: AbstractScalarDecoder(), - # character string types - char.UTF8String.typeId: AbstractScalarDecoder(), - char.NumericString.typeId: AbstractScalarDecoder(), - char.PrintableString.typeId: AbstractScalarDecoder(), - char.TeletexString.typeId: AbstractScalarDecoder(), - char.VideotexString.typeId: AbstractScalarDecoder(), - char.IA5String.typeId: AbstractScalarDecoder(), - char.GraphicString.typeId: AbstractScalarDecoder(), - char.VisibleString.typeId: AbstractScalarDecoder(), - char.GeneralString.typeId: AbstractScalarDecoder(), - char.UniversalString.typeId: AbstractScalarDecoder(), - char.BMPString.typeId: AbstractScalarDecoder(), - # useful types - useful.ObjectDescriptor.typeId: AbstractScalarDecoder(), - useful.GeneralizedTime.typeId: AbstractScalarDecoder(), - useful.UTCTime.typeId: AbstractScalarDecoder() -} - - -class Decoder(object): - - # noinspection PyDefaultArgument - def __init__(self, tagMap, typeMap): - self.__tagMap = tagMap - self.__typeMap = typeMap - - def __call__(self, pyObject, asn1Spec): - if debug.logger & debug.flagDecoder: - debug.scope.push(type(pyObject).__name__) - debug.logger('decoder called at scope %s, working with type %s' % (debug.scope, type(pyObject).__name__)) - - if asn1Spec is None or not isinstance(asn1Spec, base.Asn1Item): - raise error.PyAsn1Error('asn1Spec is not valid (should be an instance of an ASN.1 Item, not %s)' % asn1Spec.__class__.__name__) - - try: - valueDecoder = self.__typeMap[asn1Spec.typeId] - except KeyError: - # use base type for codec lookup to recover untagged types - baseTagSet = tag.TagSet(asn1Spec.tagSet.baseTag, asn1Spec.tagSet.baseTag) - try: - valueDecoder = self.__tagMap[baseTagSet] - except KeyError: - raise error.PyAsn1Error('Unknown ASN.1 tag %s' % asn1Spec.tagSet) - - if debug.logger & debug.flagDecoder: - debug.logger('calling decoder %s on Python type %s <%s>' % (type(valueDecoder).__name__, type(pyObject).__name__, repr(pyObject))) - - value = valueDecoder(pyObject, asn1Spec, self) - - if debug.logger & debug.flagDecoder: - debug.logger('decoder %s produced ASN.1 type %s <%s>' % (type(valueDecoder).__name__, type(value).__name__, repr(value))) - debug.scope.pop() - - return value - - -#: Turns Python objects of built-in types into ASN.1 objects. -#: -#: Takes Python objects of built-in types and turns them into a tree of -#: ASN.1 objects (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) which -#: may be a scalar or an arbitrary nested structure. -#: -#: Parameters -#: ---------- -#: pyObject: :py:class:`object` -#: A scalar or nested Python objects -#: -#: asn1Spec: any pyasn1 type object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative -#: A pyasn1 type object to act as a template guiding the decoder. It is required -#: for successful interpretation of Python objects mapping into their ASN.1 -#: representations. -#: -#: Returns -#: ------- -#: : :py:class:`~pyasn1.type.base.PyAsn1Item` derivative -#: A scalar or constructed pyasn1 object -#: -#: Raises -#: ------ -#: : :py:class:`pyasn1.error.PyAsn1Error` -#: On decoding errors -decode = Decoder(tagMap, typeMap) diff --git a/src/lib/pyasn1/codec/native/encoder.py b/src/lib/pyasn1/codec/native/encoder.py deleted file mode 100644 index afeb8ae0..00000000 --- a/src/lib/pyasn1/codec/native/encoder.py +++ /dev/null @@ -1,215 +0,0 @@ -# -# This file is part of pyasn1 software. -# -# Copyright (c) 2005-2017, Ilya Etingof -# License: http://pyasn1.sf.net/license.html -# -try: - from collections import OrderedDict - -except ImportError: - OrderedDict = dict - -from pyasn1.type import base, univ, char, useful -from pyasn1 import debug, error - -__all__ = ['encode'] - - -class AbstractItemEncoder(object): - def encode(self, encodeFun, value): - raise error.PyAsn1Error('Not implemented') - - -class ExplicitlyTaggedItemEncoder(AbstractItemEncoder): - def encode(self, encodeFun, value): - if isinstance(value, base.AbstractConstructedAsn1Item): - value = value.clone(tagSet=value.tagSet[:-1], - cloneValueFlag=1) - else: - value = value.clone(tagSet=value.tagSet[:-1]) - return encodeFun(value) - -explicitlyTaggedItemEncoder = ExplicitlyTaggedItemEncoder() - - -class BooleanEncoder(AbstractItemEncoder): - def encode(self, encodeFun, value): - return bool(value) - - -class IntegerEncoder(AbstractItemEncoder): - def encode(self, encodeFun, value): - return int(value) - - -class BitStringEncoder(AbstractItemEncoder): - def encode(self, encodeFun, value): - return str(value) - - -class OctetStringEncoder(AbstractItemEncoder): - def encode(self, encodeFun, value): - return value.asOctets() - - -class TextStringEncoder(AbstractItemEncoder): - def encode(self, encodeFun, value): - return value.prettyPrint() - - -class NullEncoder(AbstractItemEncoder): - def encode(self, encodeFun, value): - return None - - -class ObjectIdentifierEncoder(AbstractItemEncoder): - def encode(self, encodeFun, value): - return str(value) - - -class RealEncoder(AbstractItemEncoder): - def encode(self, encodeFun, value): - return float(value) - - -class SetEncoder(AbstractItemEncoder): - protoDict = dict - def encode(self, encodeFun, value): - value.verifySizeSpec() - namedTypes = value.getComponentType() - substrate = self.protoDict() - for idx, (key, subValue) in enumerate(value.items()): - if namedTypes[idx].isOptional and not value[idx].isValue: - continue - substrate[key] = encodeFun(subValue) - return substrate - - -class SequenceEncoder(SetEncoder): - protoDict = OrderedDict - - -class SequenceOfEncoder(AbstractItemEncoder): - def encode(self, encodeFun, value): - value.verifySizeSpec() - return [encodeFun(x) for x in value] - - -class ChoiceEncoder(SequenceEncoder): - pass - - -class AnyEncoder(AbstractItemEncoder): - def encode(self, encodeFun, value): - return value.asOctets() - - -tagMap = { - univ.Boolean.tagSet: BooleanEncoder(), - univ.Integer.tagSet: IntegerEncoder(), - univ.BitString.tagSet: BitStringEncoder(), - univ.OctetString.tagSet: OctetStringEncoder(), - univ.Null.tagSet: NullEncoder(), - univ.ObjectIdentifier.tagSet: ObjectIdentifierEncoder(), - univ.Enumerated.tagSet: IntegerEncoder(), - univ.Real.tagSet: RealEncoder(), - # Sequence & Set have same tags as SequenceOf & SetOf - univ.SequenceOf.tagSet: SequenceOfEncoder(), - univ.SetOf.tagSet: SequenceOfEncoder(), - univ.Choice.tagSet: ChoiceEncoder(), - # character string types - char.UTF8String.tagSet: TextStringEncoder(), - char.NumericString.tagSet: TextStringEncoder(), - char.PrintableString.tagSet: TextStringEncoder(), - char.TeletexString.tagSet: TextStringEncoder(), - char.VideotexString.tagSet: TextStringEncoder(), - char.IA5String.tagSet: TextStringEncoder(), - char.GraphicString.tagSet: TextStringEncoder(), - char.VisibleString.tagSet: TextStringEncoder(), - char.GeneralString.tagSet: TextStringEncoder(), - char.UniversalString.tagSet: TextStringEncoder(), - char.BMPString.tagSet: TextStringEncoder(), - # useful types - useful.ObjectDescriptor.tagSet: OctetStringEncoder(), - useful.GeneralizedTime.tagSet: OctetStringEncoder(), - useful.UTCTime.tagSet: OctetStringEncoder() -} - -# Type-to-codec map for ambiguous ASN.1 types -typeMap = { - univ.Set.typeId: SetEncoder(), - univ.SetOf.typeId: SequenceOfEncoder(), - univ.Sequence.typeId: SequenceEncoder(), - univ.SequenceOf.typeId: SequenceOfEncoder(), - univ.Choice.typeId: ChoiceEncoder(), - univ.Any.typeId: AnyEncoder() -} - - -class Encoder(object): - - # noinspection PyDefaultArgument - def __init__(self, tagMap, typeMap={}): - self.__tagMap = tagMap - self.__typeMap = typeMap - - def __call__(self, asn1Value): - if not isinstance(asn1Value, base.Asn1Item): - raise error.PyAsn1Error('value is not valid (should be an instance of an ASN.1 Item)') - - if debug.logger & debug.flagEncoder: - debug.scope.push(type(asn1Value).__name__) - debug.logger('encoder called for type %s <%s>' % (type(asn1Value).__name__, asn1Value.prettyPrint())) - - tagSet = asn1Value.tagSet - if len(tagSet) > 1: - concreteEncoder = explicitlyTaggedItemEncoder - else: - if asn1Value.typeId is not None and asn1Value.typeId in self.__typeMap: - concreteEncoder = self.__typeMap[asn1Value.typeId] - elif tagSet in self.__tagMap: - concreteEncoder = self.__tagMap[tagSet] - else: - tagSet = asn1Value.baseTagSet - if tagSet in self.__tagMap: - concreteEncoder = self.__tagMap[tagSet] - else: - raise error.PyAsn1Error('No encoder for %s' % (asn1Value,)) - - debug.logger & debug.flagEncoder and debug.logger('using value codec %s chosen by %s' % (type(concreteEncoder).__name__, tagSet)) - - pyObject = concreteEncoder.encode(self, asn1Value) - - if debug.logger & debug.flagEncoder: - debug.logger('encoder %s produced: %s' % (type(concreteEncoder).__name__, repr(pyObject))) - debug.scope.pop() - - return pyObject - - -#: Turns ASN.1 object into a Python built-in type object(s). -#: -#: Takes any ASN.1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) -#: walks all its components recursively and produces a Python built-in type or a tree -#: of those. -#: -#: One exception is that instead of :py:class:`dict`, the :py:class:`OrderedDict` -#: can be produced (whenever available) to preserve ordering of the components -#: in ASN.1 SEQUENCE. -#: -#: Parameters -#: ---------- -# asn1Value: any pyasn1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) -#: pyasn1 object to encode (or a tree of them) -#: -#: Returns -#: ------- -#: : :py:class:`object` -#: Python built-in type instance (or a tree of them) -#: -#: Raises -#: ------ -#: : :py:class:`pyasn1.error.PyAsn1Error` -#: On encoding errors -encode = Encoder(tagMap, typeMap) diff --git a/src/lib/pyasn1/compat/__init__.py b/src/lib/pyasn1/compat/__init__.py deleted file mode 100644 index 8c3066b2..00000000 --- a/src/lib/pyasn1/compat/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# This file is necessary to make this directory a package. diff --git a/src/lib/pyasn1/compat/binary.py b/src/lib/pyasn1/compat/binary.py deleted file mode 100644 index 65c42c74..00000000 --- a/src/lib/pyasn1/compat/binary.py +++ /dev/null @@ -1,25 +0,0 @@ -# -# This file is part of pyasn1 software. -# -# Copyright (c) 2005-2017, Ilya Etingof -# License: http://pyasn1.sf.net/license.html -# -from sys import version_info - -if version_info[0:2] < (2, 6): - def bin(value): - bitstring = [] - - while value: - if value & 1 == 1: - bitstring.append('1') - else: - bitstring.append('0') - - value >>= 1 - - bitstring.reverse() - - return '0b' + ''.join(bitstring) -else: - bin = bin diff --git a/src/lib/pyasn1/compat/integer.py b/src/lib/pyasn1/compat/integer.py deleted file mode 100644 index ae9c7e1d..00000000 --- a/src/lib/pyasn1/compat/integer.py +++ /dev/null @@ -1,96 +0,0 @@ -# -# This file is part of pyasn1 software. -# -# Copyright (c) 2005-2017, Ilya Etingof -# License: http://pyasn1.sf.net/license.html -# -import sys -if sys.version_info[0:2] < (3, 2): - from binascii import a2b_hex, b2a_hex -from pyasn1.compat.octets import oct2int, null - -if sys.version_info[0:2] < (3, 2): - def from_bytes(octets, signed=False): - value = long(b2a_hex(str(octets)), 16) - - if signed and oct2int(octets[0]) & 0x80: - return value - (1 << len(octets) * 8) - - return value - - def to_bytes(value, signed=False, length=0): - if value < 0: - if signed: - bits = bitLength(value) - - # two's complement form - maxValue = 1 << bits - valueToEncode = (value + maxValue) % maxValue - - else: - raise OverflowError('can\'t convert negative int to unsigned') - elif value == 0 and length == 0: - return null - else: - bits = 0 - valueToEncode = value - - hexValue = hex(valueToEncode)[2:] - if hexValue.endswith('L'): - hexValue = hexValue[:-1] - - if len(hexValue) & 1: - hexValue = '0' + hexValue - - # padding may be needed for two's complement encoding - if value != valueToEncode or length: - hexLength = len(hexValue) * 4 - - padLength = max(length, bits) - - if padLength > hexLength: - hexValue = '00' * ((padLength - hexLength - 1) // 8 + 1) + hexValue - elif length and hexLength - length > 7: - raise OverflowError('int too big to convert') - - firstOctet = int(hexValue[:2], 16) - - if signed: - if firstOctet & 0x80: - if value >= 0: - hexValue = '00' + hexValue - elif value < 0: - hexValue = 'ff' + hexValue - - octets_value = a2b_hex(hexValue) - - return octets_value - - def bitLength(number): - # bits in unsigned number - hexValue = hex(abs(number)) - bits = len(hexValue) - 2 - if hexValue.endswith('L'): - bits -= 1 - if bits & 1: - bits += 1 - bits *= 4 - # TODO: strip lhs zeros - return bits - -else: - - def from_bytes(octets, signed=False): - return int.from_bytes(bytes(octets), 'big', signed=signed) - - def to_bytes(value, signed=False, length=0): - length = max(value.bit_length(), length) - - if signed and length % 8 == 0: - length += 1 - - return value.to_bytes(length // 8 + (length % 8 and 1 or 0), 'big', signed=signed) - - def bitLength(number): - return int(number).bit_length() - diff --git a/src/lib/pyasn1/compat/octets.py b/src/lib/pyasn1/compat/octets.py deleted file mode 100644 index ec497a68..00000000 --- a/src/lib/pyasn1/compat/octets.py +++ /dev/null @@ -1,46 +0,0 @@ -# -# This file is part of pyasn1 software. -# -# Copyright (c) 2005-2017, Ilya Etingof -# License: http://pyasn1.sf.net/license.html -# -from sys import version_info - -if version_info[0] <= 2: - int2oct = chr - # noinspection PyPep8 - ints2octs = lambda s: ''.join([int2oct(x) for x in s]) - null = '' - oct2int = ord - # noinspection PyPep8 - octs2ints = lambda s: [oct2int(x) for x in s] - # noinspection PyPep8 - str2octs = lambda x: x - # noinspection PyPep8 - octs2str = lambda x: x - # noinspection PyPep8 - isOctetsType = lambda s: isinstance(s, str) - # noinspection PyPep8 - isStringType = lambda s: isinstance(s, (str, unicode)) - # noinspection PyPep8 - ensureString = str -else: - ints2octs = bytes - # noinspection PyPep8 - int2oct = lambda x: ints2octs((x,)) - null = ints2octs() - # noinspection PyPep8 - oct2int = lambda x: x - # noinspection PyPep8 - octs2ints = lambda x: x - # noinspection PyPep8 - str2octs = lambda x: x.encode('iso-8859-1') - # noinspection PyPep8 - octs2str = lambda x: x.decode('iso-8859-1') - # noinspection PyPep8 - isOctetsType = lambda s: isinstance(s, bytes) - # noinspection PyPep8 - isStringType = lambda s: isinstance(s, str) - # noinspection PyPep8 - ensureString = bytes - diff --git a/src/lib/pyasn1/debug.py b/src/lib/pyasn1/debug.py deleted file mode 100644 index 04a9da5c..00000000 --- a/src/lib/pyasn1/debug.py +++ /dev/null @@ -1,130 +0,0 @@ -# -# This file is part of pyasn1 software. -# -# Copyright (c) 2005-2017, Ilya Etingof -# License: http://pyasn1.sf.net/license.html -# -import logging -from pyasn1.compat.octets import octs2ints -from pyasn1 import error -from pyasn1 import __version__ - -__all__ = ['Debug', 'setLogger', 'hexdump'] - -flagNone = 0x0000 -flagEncoder = 0x0001 -flagDecoder = 0x0002 -flagAll = 0xffff - -flagMap = { - 'encoder': flagEncoder, - 'decoder': flagDecoder, - 'all': flagAll -} - - -class Printer(object): - # noinspection PyShadowingNames - def __init__(self, logger=None, handler=None, formatter=None): - if logger is None: - logger = logging.getLogger('pyasn1') - logger.setLevel(logging.DEBUG) - if handler is None: - handler = logging.StreamHandler() - if formatter is None: - formatter = logging.Formatter('%(asctime)s %(name)s: %(message)s') - handler.setFormatter(formatter) - handler.setLevel(logging.DEBUG) - logger.addHandler(handler) - self.__logger = logger - - def __call__(self, msg): - self.__logger.debug(msg) - - def __str__(self): - return '' - - -if hasattr(logging, 'NullHandler'): - NullHandler = logging.NullHandler -else: - # Python 2.6 and older - class NullHandler(logging.Handler): - def emit(self, record): - pass - - -class Debug(object): - defaultPrinter = None - - def __init__(self, *flags, **options): - self._flags = flagNone - if options.get('printer') is not None: - self._printer = options.get('printer') - elif self.defaultPrinter is not None: - self._printer = self.defaultPrinter - if 'loggerName' in options: - # route our logs to parent logger - self._printer = Printer( - logger=logging.getLogger(options['loggerName']), - handler=NullHandler() - ) - else: - self._printer = Printer() - self('running pyasn1 version %s' % __version__) - for f in flags: - inverse = f and f[0] in ('!', '~') - if inverse: - f = f[1:] - try: - if inverse: - self._flags &= ~flagMap[f] - else: - self._flags |= flagMap[f] - except KeyError: - raise error.PyAsn1Error('bad debug flag %s' % f) - - self('debug category \'%s\' %s' % (f, inverse and 'disabled' or 'enabled')) - - def __str__(self): - return 'logger %s, flags %x' % (self._printer, self._flags) - - def __call__(self, msg): - self._printer(msg) - - def __and__(self, flag): - return self._flags & flag - - def __rand__(self, flag): - return flag & self._flags - - -logger = 0 - - -def setLogger(l): - global logger - logger = l - - -def hexdump(octets): - return ' '.join( - ['%s%.2X' % (n % 16 == 0 and ('\n%.5d: ' % n) or '', x) - for n, x in zip(range(len(octets)), octs2ints(octets))] - ) - - -class Scope(object): - def __init__(self): - self._list = [] - - def __str__(self): return '.'.join(self._list) - - def push(self, token): - self._list.append(token) - - def pop(self): - return self._list.pop() - - -scope = Scope() diff --git a/src/lib/pyasn1/error.py b/src/lib/pyasn1/error.py deleted file mode 100644 index 85308557..00000000 --- a/src/lib/pyasn1/error.py +++ /dev/null @@ -1,18 +0,0 @@ -# -# This file is part of pyasn1 software. -# -# Copyright (c) 2005-2017, Ilya Etingof -# License: http://pyasn1.sf.net/license.html -# - - -class PyAsn1Error(Exception): - pass - - -class ValueConstraintError(PyAsn1Error): - pass - - -class SubstrateUnderrunError(PyAsn1Error): - pass diff --git a/src/lib/pyasn1/type/__init__.py b/src/lib/pyasn1/type/__init__.py deleted file mode 100644 index 8c3066b2..00000000 --- a/src/lib/pyasn1/type/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# This file is necessary to make this directory a package. diff --git a/src/lib/pyasn1/type/base.py b/src/lib/pyasn1/type/base.py deleted file mode 100644 index 00c329c2..00000000 --- a/src/lib/pyasn1/type/base.py +++ /dev/null @@ -1,617 +0,0 @@ -# -# This file is part of pyasn1 software. -# -# Copyright (c) 2005-2017, Ilya Etingof -# License: http://pyasn1.sf.net/license.html -# -import sys -from pyasn1.type import constraint, tagmap, tag -from pyasn1 import error - -__all__ = ['Asn1Item', 'Asn1ItemBase', 'AbstractSimpleAsn1Item', 'AbstractConstructedAsn1Item'] - - -class Asn1Item(object): - @classmethod - def getTypeId(cls, increment=1): - try: - Asn1Item._typeCounter += increment - except AttributeError: - Asn1Item._typeCounter = increment - return Asn1Item._typeCounter - - -class Asn1ItemBase(Asn1Item): - #: Set or return a :py:class:`~pyasn1.type.tag.TagSet` object representing - #: ASN.1 tag(s) associated with |ASN.1| type. - tagSet = tag.TagSet() - - #: Default :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` - #: object imposing constraints on initialization values. - subtypeSpec = constraint.ConstraintsIntersection() - - # Disambiguation ASN.1 types identification - typeId = None - - def __init__(self, tagSet=None, subtypeSpec=None): - if tagSet is None: - self._tagSet = self.__class__.tagSet - else: - self._tagSet = tagSet - if subtypeSpec is None: - self._subtypeSpec = self.__class__.subtypeSpec - else: - self._subtypeSpec = subtypeSpec - - @property - def effectiveTagSet(self): - """For |ASN.1| type is equivalent to *tagSet* - """ - return self._tagSet # used by untagged types - - @property - def tagMap(self): - """Return a :class:`~pyasn1.type.tagmap.TagMap` object mapping ASN.1 tags to ASN.1 objects within callee object. - """ - try: - return self._tagMap - - except AttributeError: - self._tagMap = tagmap.TagMap({self._tagSet: self}) - return self._tagMap - - def isSameTypeWith(self, other, matchTags=True, matchConstraints=True): - """Examine |ASN.1| type for equality with other ASN.1 type. - - ASN.1 tags (:py:mod:`~pyasn1.type.tag`) and constraints - (:py:mod:`~pyasn1.type.constraint`) are examined when carrying - out ASN.1 types comparison. - - No Python inheritance relationship between PyASN1 objects is considered. - - Parameters - ---------- - other: a pyasn1 type object - Class instance representing ASN.1 type. - - Returns - ------- - : :class:`bool` - :class:`True` if *other* is |ASN.1| type, - :class:`False` otherwise. - """ - return self is other or \ - (not matchTags or - self._tagSet == other.tagSet) and \ - (not matchConstraints or - self._subtypeSpec == other.subtypeSpec) - - def isSuperTypeOf(self, other, matchTags=True, matchConstraints=True): - """Examine |ASN.1| type for subtype relationship with other ASN.1 type. - - ASN.1 tags (:py:mod:`~pyasn1.type.tag`) and constraints - (:py:mod:`~pyasn1.type.constraint`) are examined when carrying - out ASN.1 types comparison. - - No Python inheritance relationship between PyASN1 objects is considered. - - - Parameters - ---------- - other: a pyasn1 type object - Class instance representing ASN.1 type. - - Returns - ------- - : :class:`bool` - :class:`True` if *other* is a subtype of |ASN.1| type, - :class:`False` otherwise. - """ - return (not matchTags or - self._tagSet.isSuperTagSetOf(other.tagSet)) and \ - (not matchConstraints or - (self._subtypeSpec.isSuperTypeOf(other.subtypeSpec))) - - @staticmethod - def isNoValue(*values): - for value in values: - if value is not None and value is not noValue: - return False - return True - - # backward compatibility - - def getTagSet(self): - return self.tagSet - - def getEffectiveTagSet(self): - return self.effectiveTagSet - - def getTagMap(self): - return self.tagMap - - def getSubtypeSpec(self): - return self.subtypeSpec - - -class NoValue(object): - """Create a singleton instance of NoValue class. - - NoValue object can be used as an initializer on PyASN1 type class - instantiation to represent ASN.1 type rather than ASN.1 data value. - - No operations other than type comparison can be performed on - a PyASN1 type object. - """ - skipMethods = ('__getattribute__', '__getattr__', '__setattr__', '__delattr__', - '__class__', '__init__', '__del__', '__new__', '__repr__', - '__qualname__', '__objclass__', 'im_class', '__sizeof__') - - _instance = None - - def __new__(cls): - if cls._instance is None: - def getPlug(name): - def plug(self, *args, **kw): - raise error.PyAsn1Error('Uninitialized ASN.1 value ("%s" attribute looked up)' % name) - return plug - - op_names = [name - for typ in (str, int, list, dict) - for name in dir(typ) - if name not in cls.skipMethods and name.startswith('__') and name.endswith('__') and callable(getattr(typ, name))] - - for name in set(op_names): - setattr(cls, name, getPlug(name)) - - cls._instance = object.__new__(cls) - - return cls._instance - - def __getattr__(self, attr): - if attr in self.skipMethods: - raise AttributeError('attribute %s not present' % attr) - raise error.PyAsn1Error('No value for "%s"' % attr) - - def __repr__(self): - return '%s()' % self.__class__.__name__ - -noValue = NoValue() - - -# Base class for "simple" ASN.1 objects. These are immutable. -class AbstractSimpleAsn1Item(Asn1ItemBase): - #: Default payload value - defaultValue = noValue - - def __init__(self, value=noValue, tagSet=None, subtypeSpec=None): - Asn1ItemBase.__init__(self, tagSet, subtypeSpec) - if value is None or value is noValue: - value = self.defaultValue - else: - value = self.prettyIn(value) - try: - self._subtypeSpec(value) - - except error.PyAsn1Error: - exType, exValue, exTb = sys.exc_info() - raise exType('%s at %s' % (exValue, self.__class__.__name__)) - - self.__hashedValue = None - self._value = value - self._len = None - - def __repr__(self): - representation = [] - if self._value is not self.defaultValue: - representation.append(self.prettyOut(self._value)) - if self._tagSet is not self.__class__.tagSet: - representation.append('tagSet=%r' % (self._tagSet,)) - if self._subtypeSpec is not self.subtypeSpec: - representation.append('subtypeSpec=%r' % (self._subtypeSpec,)) - return '%s(%s)' % (self.__class__.__name__, ', '.join(representation)) - - def __str__(self): - return str(self._value) - - def __eq__(self, other): - return self is other and True or self._value == other - - def __ne__(self, other): - return self._value != other - - def __lt__(self, other): - return self._value < other - - def __le__(self, other): - return self._value <= other - - def __gt__(self, other): - return self._value > other - - def __ge__(self, other): - return self._value >= other - - if sys.version_info[0] <= 2: - def __nonzero__(self): - return self._value and True or False - else: - def __bool__(self): - return self._value and True or False - - def __hash__(self): - if self.__hashedValue is None: - self.__hashedValue = hash(self._value) - return self.__hashedValue - - @property - def isValue(self): - """Indicate if |ASN.1| object represents ASN.1 type or ASN.1 value. - - The PyASN1 type objects can only participate in types comparison - and serve as a blueprint for serialization codecs to resolve - ambiguous types. - - The PyASN1 value objects can additionally participate in most - of built-in Python operations. - - Returns - ------- - : :class:`bool` - :class:`True` if object represents ASN.1 value and type, - :class:`False` if object represents just ASN.1 type. - - """ - return self._value is not noValue - - def clone(self, value=noValue, tagSet=None, subtypeSpec=None): - """Create a copy of a |ASN.1| type or object. - - Any parameters to the *clone()* method will replace corresponding - properties of the |ASN.1| object. - - Parameters - ---------- - value: :class:`tuple`, :class:`str` or |ASN.1| object - Initialization value to pass to new ASN.1 object instead of - inheriting one from the caller. - - tagSet: :py:class:`~pyasn1.type.tag.TagSet` - Object representing ASN.1 tag(s) to use in new object instead of inheriting from the caller - - subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` - Object representing ASN.1 subtype constraint(s) to use in new object instead of inheriting from the caller - - Returns - ------- - : - new instance of |ASN.1| type/value - """ - isModified = False - - if value is None or value is noValue: - value = self._value - else: - isModified = True - if tagSet is None or tagSet is noValue: - tagSet = self._tagSet - else: - isModified = True - if subtypeSpec is None or subtypeSpec is noValue: - subtypeSpec = self._subtypeSpec - else: - isModified = True - - if isModified: - return self.__class__(value, tagSet, subtypeSpec) - else: - return self - - def subtype(self, value=noValue, implicitTag=None, explicitTag=None, - subtypeSpec=None): - """Create a copy of a |ASN.1| type or object. - - Any parameters to the *subtype()* method will be added to the corresponding - properties of the |ASN.1| object. - - Parameters - ---------- - value: :class:`tuple`, :class:`str` or |ASN.1| object - Initialization value to pass to new ASN.1 object instead of - inheriting one from the caller. - - implicitTag: :py:class:`~pyasn1.type.tag.Tag` - Implicitly apply given ASN.1 tag object to caller's - :py:class:`~pyasn1.type.tag.TagSet`, then use the result as - new object's ASN.1 tag(s). - - explicitTag: :py:class:`~pyasn1.type.tag.Tag` - Explicitly apply given ASN.1 tag object to caller's - :py:class:`~pyasn1.type.tag.TagSet`, then use the result as - new object's ASN.1 tag(s). - - subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` - Add ASN.1 constraints object to one of the caller, then - use the result as new object's ASN.1 constraints. - - Returns - ------- - : - new instance of |ASN.1| type/value - """ - isModified = False - - if value is None or value is noValue: - value = self._value - else: - isModified = True - if implicitTag is not None and implicitTag is not noValue: - tagSet = self._tagSet.tagImplicitly(implicitTag) - isModified = True - elif explicitTag is not None and explicitTag is not noValue: - tagSet = self._tagSet.tagExplicitly(explicitTag) - isModified = True - else: - tagSet = self._tagSet - if subtypeSpec is None or subtypeSpec is noValue: - subtypeSpec = self._subtypeSpec - else: - subtypeSpec = self._subtypeSpec + subtypeSpec - isModified = True - - if isModified: - return self.__class__(value, tagSet, subtypeSpec) - else: - return self - - def prettyIn(self, value): - return value - - def prettyOut(self, value): - return str(value) - - def prettyPrint(self, scope=0): - """Provide human-friendly printable object representation. - - Returns - ------- - : :class:`str` - human-friendly type and/or value representation. - """ - if self.isValue: - return self.prettyOut(self._value) - else: - return '' - - # XXX Compatibility stub - def prettyPrinter(self, scope=0): - return self.prettyPrint(scope) - - # noinspection PyUnusedLocal - def prettyPrintType(self, scope=0): - return '%s -> %s' % (self.tagSet, self.__class__.__name__) - - # backward compatibility - - def hasValue(self): - return self.isValue - - -# -# Constructed types: -# * There are five of them: Sequence, SequenceOf/SetOf, Set and Choice -# * ASN1 types and values are represened by Python class instances -# * Value initialization is made for defaulted components only -# * Primary method of component addressing is by-position. Data model for base -# type is Python sequence. Additional type-specific addressing methods -# may be implemented for particular types. -# * SequenceOf and SetOf types do not implement any additional methods -# * Sequence, Set and Choice types also implement by-identifier addressing -# * Sequence, Set and Choice types also implement by-asn1-type (tag) addressing -# * Sequence and Set types may include optional and defaulted -# components -# * Constructed types hold a reference to component types used for value -# verification and ordering. -# * Component type is a scalar type for SequenceOf/SetOf types and a list -# of types for Sequence/Set/Choice. -# - -def setupComponent(): - """Returns a sentinel value. - - Indicates to a constructed type to set up its inner component so that it - can be referred to. This is useful in situation when you want to populate - descendants of a constructed type what requires being able to refer to - their parent types along the way. - - Example - ------- - - >>> constructed['record'] = setupComponent() - >>> constructed['record']['scalar'] = 42 - """ - return noValue - - -class AbstractConstructedAsn1Item(Asn1ItemBase): - - #: If `True`, requires exact component type matching, - #: otherwise subtype relation is only enforced - strictConstraints = False - - def __init__(self, componentType=None, tagSet=None, - subtypeSpec=None, sizeSpec=None): - Asn1ItemBase.__init__(self, tagSet, subtypeSpec) - if componentType is None: - self._componentType = self.componentType - else: - self._componentType = componentType - if sizeSpec is None: - self._sizeSpec = self.sizeSpec - else: - self._sizeSpec = sizeSpec - self._componentValues = [] - - def __repr__(self): - representation = [] - if self._componentType is not self.componentType: - representation.append('componentType=%r' % (self._componentType,)) - if self._tagSet is not self.__class__.tagSet: - representation.append('tagSet=%r' % (self._tagSet,)) - if self._subtypeSpec is not self.subtypeSpec: - representation.append('subtypeSpec=%r' % (self._subtypeSpec,)) - representation = '%s(%s)' % (self.__class__.__name__, ', '.join(representation)) - if self._componentValues: - for idx, component in enumerate(self._componentValues): - if component is None or component is noValue: - continue - representation += '.setComponentByPosition(%d, %s)' % (idx, repr(component)) - return representation - - def __eq__(self, other): - return self is other and True or self._componentValues == other - - def __ne__(self, other): - return self._componentValues != other - - def __lt__(self, other): - return self._componentValues < other - - def __le__(self, other): - return self._componentValues <= other - - def __gt__(self, other): - return self._componentValues > other - - def __ge__(self, other): - return self._componentValues >= other - - if sys.version_info[0] <= 2: - def __nonzero__(self): - return self._componentValues and True or False - else: - def __bool__(self): - return self._componentValues and True or False - - def _cloneComponentValues(self, myClone, cloneValueFlag): - pass - - def clone(self, tagSet=None, subtypeSpec=None, sizeSpec=None, cloneValueFlag=None): - """Create a copy of a |ASN.1| type or object. - - Any parameters to the *clone()* method will replace corresponding - properties of the |ASN.1| object. - - Parameters - ---------- - tagSet: :py:class:`~pyasn1.type.tag.TagSet` - Object representing non-default ASN.1 tag(s) - - subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` - Object representing non-default ASN.1 subtype constraint(s) - - sizeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` - Object representing non-default ASN.1 size constraint(s) - - Returns - ------- - : - new instance of |ASN.1| type/value - - """ - if tagSet is None: - tagSet = self._tagSet - if subtypeSpec is None: - subtypeSpec = self._subtypeSpec - if sizeSpec is None: - sizeSpec = self._sizeSpec - clone = self.__class__(self._componentType, tagSet, subtypeSpec, sizeSpec) - if cloneValueFlag: - self._cloneComponentValues(clone, cloneValueFlag) - return clone - - def subtype(self, implicitTag=None, explicitTag=None, subtypeSpec=None, - sizeSpec=None, cloneValueFlag=None): - """Create a copy of a |ASN.1| type or object. - - Any parameters to the *subtype()* method will be added to the corresponding - properties of the |ASN.1| object. - - Parameters - ---------- - tagSet: :py:class:`~pyasn1.type.tag.TagSet` - Object representing non-default ASN.1 tag(s) - - subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` - Object representing non-default ASN.1 subtype constraint(s) - - sizeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` - Object representing non-default ASN.1 size constraint(s) - - Returns - ------- - : - new instance of |ASN.1| type/value - - """ - if implicitTag is not None and implicitTag is not noValue: - tagSet = self._tagSet.tagImplicitly(implicitTag) - elif explicitTag is not None and explicitTag is not noValue: - tagSet = self._tagSet.tagExplicitly(explicitTag) - else: - tagSet = self._tagSet - if subtypeSpec is None or subtypeSpec is noValue: - subtypeSpec = self._subtypeSpec - else: - subtypeSpec = self._subtypeSpec + subtypeSpec - if sizeSpec is None or sizeSpec is noValue: - sizeSpec = self._sizeSpec - else: - sizeSpec += self._sizeSpec - clone = self.__class__(self._componentType, tagSet, subtypeSpec, sizeSpec) - if cloneValueFlag: - self._cloneComponentValues(clone, cloneValueFlag) - return clone - - def verifySizeSpec(self): - self._sizeSpec(self) - - def getComponentByPosition(self, idx): - raise error.PyAsn1Error('Method not implemented') - - def setComponentByPosition(self, idx, value, verifyConstraints=True): - raise error.PyAsn1Error('Method not implemented') - - def setComponents(self, *args, **kwargs): - for idx, value in enumerate(args): - self[idx] = value - for k in kwargs: - self[k] = kwargs[k] - return self - - def getComponentType(self): - return self._componentType - - # backward compatibility -- no-op - def setDefaultComponents(self): - pass - - @property - def componentTagMap(self): - raise error.PyAsn1Error('Method not implemented') - - def __getitem__(self, idx): - return self.getComponentByPosition(idx) - - def __setitem__(self, idx, value): - self.setComponentByPosition(idx, value) - - def __len__(self): - return len(self._componentValues) - - def clear(self): - self._componentValues = [] - - # backward compatibility - def getComponentTagMap(self): - return self.componentTagMap \ No newline at end of file diff --git a/src/lib/pyasn1/type/char.py b/src/lib/pyasn1/type/char.py deleted file mode 100644 index 039e5366..00000000 --- a/src/lib/pyasn1/type/char.py +++ /dev/null @@ -1,378 +0,0 @@ -# -# This file is part of pyasn1 software. -# -# Copyright (c) 2005-2017, Ilya Etingof -# License: http://pyasn1.sf.net/license.html -# -import sys -from pyasn1.type import univ, tag -from pyasn1 import error - - -__all__ = ['NumericString', 'PrintableString', 'TeletexString', 'T61String', 'VideotexString', - 'IA5String', 'GraphicString', 'VisibleString', 'ISO646String', - 'GeneralString', 'UniversalString', 'BMPString', 'UTF8String'] - -NoValue = univ.NoValue -noValue = univ.noValue - - -class AbstractCharacterString(univ.OctetString): - """Creates |ASN.1| type or object. - - |ASN.1| objects are immutable and duck-type Python 2 :class:`unicode` or Python 3 :class:`str`. - When used in octet-stream context, |ASN.1| type assumes "|encoding|" encoding. - - Parameters - ---------- - value: :class:`unicode`, :class:`str`, :class:`bytes` or |ASN.1| object - unicode object (Python 2) or string (Python 3), alternatively string - (Python 2) or bytes (Python 3) representing octet-stream of serialized - unicode string (note `encoding` parameter) or |ASN.1| class instance. - - tagSet: :py:class:`~pyasn1.type.tag.TagSet` - Object representing non-default ASN.1 tag(s) - - subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` - Object representing non-default ASN.1 subtype constraint(s) - - encoding: :py:class:`str` - Unicode codec ID to encode/decode :class:`unicode` (Python 2) or - :class:`str` (Python 3) the payload when |ASN.1| object is used - in octet-stream context. - - Raises - ------ - : :py:class:`pyasn1.error.PyAsn1Error` - On constraint violation or bad initializer. - """ - - if sys.version_info[0] <= 2: - def __str__(self): - try: - return self._value.encode(self._encoding) - except UnicodeEncodeError: - raise error.PyAsn1Error( - 'Can\'t encode string \'%s\' with \'%s\' codec' % (self._value, self._encoding) - ) - - def __unicode__(self): - return unicode(self._value) - - def prettyIn(self, value): - if isinstance(value, unicode): - return value - elif isinstance(value, str): - try: - return value.decode(self._encoding) - except (LookupError, UnicodeDecodeError): - raise error.PyAsn1Error( - 'Can\'t decode string \'%s\' with \'%s\' codec' % (value, self._encoding) - ) - elif isinstance(value, (tuple, list)): - try: - return self.prettyIn(''.join([chr(x) for x in value])) - except ValueError: - raise error.PyAsn1Error( - 'Bad %s initializer \'%s\'' % (self.__class__.__name__, value) - ) - else: - try: - return unicode(value) - except UnicodeDecodeError: - raise error.PyAsn1Error( - 'Can\'t turn object \'%s\' into unicode' % (value,) - ) - - def asOctets(self, padding=True): - return str(self) - - def asNumbers(self, padding=True): - return tuple([ord(x) for x in str(self)]) - - else: - def __str__(self): - return str(self._value) - - def __bytes__(self): - try: - return self._value.encode(self._encoding) - except UnicodeEncodeError: - raise error.PyAsn1Error( - 'Can\'t encode string \'%s\' with \'%s\' codec' % (self._value, self._encoding) - ) - - def prettyIn(self, value): - if isinstance(value, str): - return value - elif isinstance(value, bytes): - try: - return value.decode(self._encoding) - except UnicodeDecodeError: - raise error.PyAsn1Error( - 'Can\'t decode string \'%s\' with \'%s\' codec' % (value, self._encoding) - ) - elif isinstance(value, (tuple, list)): - return self.prettyIn(bytes(value)) - else: - try: - return str(value) - except (UnicodeDecodeError, ValueError): - raise error.PyAsn1Error( - 'Can\'t turn object \'%s\' into unicode' % (value,) - ) - - def asOctets(self, padding=True): - return bytes(self) - - def asNumbers(self, padding=True): - return tuple(bytes(self)) - - def prettyOut(self, value): - return value - - def __reversed__(self): - return reversed(self._value) - - def clone(self, value=noValue, tagSet=None, subtypeSpec=None, - encoding=None, binValue=noValue, hexValue=noValue): - """Creates a copy of a |ASN.1| type or object. - - Any parameters to the *clone()* method will replace corresponding - properties of the |ASN.1| object. - - Parameters - ---------- - value: :class:`unicode`, :class:`str`, :class:`bytes` or |ASN.1| object - unicode object (Python 2) or string (Python 3), alternatively string - (Python 2) or bytes (Python 3) representing octet-stream of serialized - unicode string (note `encoding` parameter) or |ASN.1| class instance. - - tagSet: :py:class:`~pyasn1.type.tag.TagSet` - Object representing non-default ASN.1 tag(s) - - subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` - Object representing non-default ASN.1 subtype constraint(s) - - encoding: :py:class:`str` - Unicode codec ID to encode/decode :py:class:`unicode` (Python 2) or - :py:class:`str` (Python 3) the payload when |ASN.1| object is used - in octet-stream context. - - Returns - ------- - : - new instance of |ASN.1| type/value - - """ - return univ.OctetString.clone(self, value, tagSet, subtypeSpec, encoding, binValue, hexValue) - - def subtype(self, value=noValue, implicitTag=None, explicitTag=None, - subtypeSpec=None, encoding=None, binValue=noValue, hexValue=noValue): - """Creates a copy of a |ASN.1| type or object. - - Any parameters to the *subtype()* method will be added to the corresponding - properties of the |ASN.1| object. - - Parameters - ---------- - value: :class:`unicode`, :class:`str`, :class:`bytes` or |ASN.1| object - unicode object (Python 2) or string (Python 3), alternatively string - (Python 2) or bytes (Python 3) representing octet-stream of serialized - unicode string (note `encoding` parameter) or |ASN.1| class instance. - - implicitTag: :py:class:`~pyasn1.type.tag.Tag` - Implicitly apply given ASN.1 tag object to caller's - :py:class:`~pyasn1.type.tag.TagSet`, then use the result as - new object's ASN.1 tag(s). - - explicitTag: :py:class:`~pyasn1.type.tag.Tag` - Explicitly apply given ASN.1 tag object to caller's - :py:class:`~pyasn1.type.tag.TagSet`, then use the result as - new object's ASN.1 tag(s). - - subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` - Object representing non-default ASN.1 subtype constraint(s) - - encoding: :py:class:`str` - Unicode codec ID to encode/decode :py:class:`unicode` (Python 2) or - :py:class:`str` (Python 3) the payload when |ASN.1| object is used - in octet-stream context. - - Returns - ------- - : - new instance of |ASN.1| type/value - - """ - return univ.OctetString.subtype(self, value, implicitTag, explicitTag, subtypeSpec, encoding, binValue, hexValue) - - -class NumericString(AbstractCharacterString): - __doc__ = AbstractCharacterString.__doc__ - - #: Set (class attribute) or return (class or instance attribute) a - #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) - #: associated with |ASN.1| type. - tagSet = AbstractCharacterString.tagSet.tagImplicitly( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 18) - ) - encoding = 'us-ascii' - - # Optimization for faster codec lookup - typeId = AbstractCharacterString.getTypeId() - - -class PrintableString(AbstractCharacterString): - __doc__ = AbstractCharacterString.__doc__ - - #: Set (class attribute) or return (class or instance attribute) a - #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) - #: associated with |ASN.1| type. - tagSet = AbstractCharacterString.tagSet.tagImplicitly( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 19) - ) - encoding = 'us-ascii' - - # Optimization for faster codec lookup - typeId = AbstractCharacterString.getTypeId() - - -class TeletexString(AbstractCharacterString): - __doc__ = AbstractCharacterString.__doc__ - - #: Set (class attribute) or return (class or instance attribute) a - #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) - #: associated with |ASN.1| type. - tagSet = AbstractCharacterString.tagSet.tagImplicitly( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 20) - ) - encoding = 'iso-8859-1' - - -class T61String(TeletexString): - __doc__ = TeletexString.__doc__ - - -class VideotexString(AbstractCharacterString): - __doc__ = AbstractCharacterString.__doc__ - - #: Set (class attribute) or return (class or instance attribute) a - #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) - #: associated with |ASN.1| type. - tagSet = AbstractCharacterString.tagSet.tagImplicitly( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 21) - ) - encoding = 'iso-8859-1' - - # Optimization for faster codec lookup - typeId = AbstractCharacterString.getTypeId() - - -class IA5String(AbstractCharacterString): - __doc__ = AbstractCharacterString.__doc__ - - #: Set (class attribute) or return (class or instance attribute) a - #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) - #: associated with |ASN.1| type. - tagSet = AbstractCharacterString.tagSet.tagImplicitly( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 22) - ) - encoding = 'us-ascii' - - # Optimization for faster codec lookup - typeId = AbstractCharacterString.getTypeId() - - -class GraphicString(AbstractCharacterString): - __doc__ = AbstractCharacterString.__doc__ - - #: Set (class attribute) or return (class or instance attribute) a - #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) - #: associated with |ASN.1| type. - tagSet = AbstractCharacterString.tagSet.tagImplicitly( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 25) - ) - encoding = 'iso-8859-1' - - # Optimization for faster codec lookup - typeId = AbstractCharacterString.getTypeId() - - -class VisibleString(AbstractCharacterString): - __doc__ = AbstractCharacterString.__doc__ - - #: Set (class attribute) or return (class or instance attribute) a - #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) - #: associated with |ASN.1| type. - tagSet = AbstractCharacterString.tagSet.tagImplicitly( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 26) - ) - encoding = 'us-ascii' - - # Optimization for faster codec lookup - typeId = AbstractCharacterString.getTypeId() - - -class ISO646String(VisibleString): - __doc__ = VisibleString.__doc__ - - -class GeneralString(AbstractCharacterString): - __doc__ = AbstractCharacterString.__doc__ - - #: Set (class attribute) or return (class or instance attribute) a - #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) - #: associated with |ASN.1| type. - tagSet = AbstractCharacterString.tagSet.tagImplicitly( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 27) - ) - encoding = 'iso-8859-1' - - # Optimization for faster codec lookup - typeId = AbstractCharacterString.getTypeId() - - -class UniversalString(AbstractCharacterString): - __doc__ = AbstractCharacterString.__doc__ - - #: Set (class attribute) or return (class or instance attribute) a - #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) - #: associated with |ASN.1| type. - tagSet = AbstractCharacterString.tagSet.tagImplicitly( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 28) - ) - encoding = "utf-32-be" - - # Optimization for faster codec lookup - typeId = AbstractCharacterString.getTypeId() - - -class BMPString(AbstractCharacterString): - __doc__ = AbstractCharacterString.__doc__ - - #: Set (class attribute) or return (class or instance attribute) a - #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) - #: associated with |ASN.1| type. - tagSet = AbstractCharacterString.tagSet.tagImplicitly( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 30) - ) - encoding = "utf-16-be" - - # Optimization for faster codec lookup - typeId = AbstractCharacterString.getTypeId() - - -class UTF8String(AbstractCharacterString): - __doc__ = AbstractCharacterString.__doc__ - - #: Set (class attribute) or return (class or instance attribute) a - #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) - #: associated with |ASN.1| type. - tagSet = AbstractCharacterString.tagSet.tagImplicitly( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 12) - ) - encoding = "utf-8" - - # Optimization for faster codec lookup - typeId = AbstractCharacterString.getTypeId() diff --git a/src/lib/pyasn1/type/constraint.py b/src/lib/pyasn1/type/constraint.py deleted file mode 100644 index 7f96c507..00000000 --- a/src/lib/pyasn1/type/constraint.py +++ /dev/null @@ -1,283 +0,0 @@ -# -# This file is part of pyasn1 software. -# -# Copyright (c) 2005-2017, Ilya Etingof -# License: http://pyasn1.sf.net/license.html -# -# Original concept and code by Mike C. Fletcher. -# -import sys -from pyasn1.type import error - -__all__ = ['SingleValueConstraint', 'ContainedSubtypeConstraint', 'ValueRangeConstraint', - 'ValueSizeConstraint', 'PermittedAlphabetConstraint', 'InnerTypeConstraint', - 'ConstraintsExclusion', 'ConstraintsIntersection', 'ConstraintsUnion'] - - -class AbstractConstraint(object): - """Abstract base-class for constraint objects - - Constraints should be stored in a simple sequence in the - namespace of their client Asn1Item sub-classes in cases - when ASN.1 constraint is define. - """ - - def __init__(self, *values): - self._valueMap = set() - self._setValues(values) - self.__hashedValues = None - - def __call__(self, value, idx=None): - if not self._values: - return - - try: - self._testValue(value, idx) - - except error.ValueConstraintError: - raise error.ValueConstraintError( - '%s failed at: %r' % (self, sys.exc_info()[1]) - ) - - def __repr__(self): - return '%s(%s)' % ( - self.__class__.__name__, - ', '.join([repr(x) for x in self._values]) - ) - - def __eq__(self, other): - return self is other and True or self._values == other - - def __ne__(self, other): - return self._values != other - - def __lt__(self, other): - return self._values < other - - def __le__(self, other): - return self._values <= other - - def __gt__(self, other): - return self._values > other - - def __ge__(self, other): - return self._values >= other - - if sys.version_info[0] <= 2: - def __nonzero__(self): - return self._values and True or False - else: - def __bool__(self): - return self._values and True or False - - def __hash__(self): - if self.__hashedValues is None: - self.__hashedValues = hash((self.__class__.__name__, self._values)) - return self.__hashedValues - - # descriptor protocol - - def __get__(self, instance, owner): - if instance is None: - return self - - # This is a bit of hack: look up instance attribute first, - # then try class attribute if instance attribute with that - # name is not available. - # The rationale is to have `.subtypeSpec`/`.sizeSpec` readable-writeable - # as a class attribute and read-only as instance attribute. - try: - return instance._subtypeSpec - - except AttributeError: - try: - return instance._sizeSpec - - except AttributeError: - return self - - def __set__(self, instance, value): - raise AttributeError('attribute is read-only') - - def _setValues(self, values): - self._values = values - - def _testValue(self, value, idx): - raise error.ValueConstraintError(value) - - # Constraints derivation logic - def getValueMap(self): - return self._valueMap - - def isSuperTypeOf(self, otherConstraint): - return (otherConstraint is self or - not self._values or - otherConstraint == self or - self in otherConstraint.getValueMap()) - - def isSubTypeOf(self, otherConstraint): - return (otherConstraint is self or - not self or - otherConstraint == self or - otherConstraint in self._valueMap) - -class SingleValueConstraint(AbstractConstraint): - """Value must be part of defined values constraint""" - - def _setValues(self, values): - self._values = values - self._set = set(values) - - def _testValue(self, value, idx): - if value not in self._set: - raise error.ValueConstraintError(value) - - -class ContainedSubtypeConstraint(AbstractConstraint): - """Value must satisfy all of defined set of constraints""" - - def _testValue(self, value, idx): - for c in self._values: - c(value, idx) - - -class ValueRangeConstraint(AbstractConstraint): - """Value must be within start and stop values (inclusive)""" - - def _testValue(self, value, idx): - if value < self.start or value > self.stop: - raise error.ValueConstraintError(value) - - def _setValues(self, values): - if len(values) != 2: - raise error.PyAsn1Error( - '%s: bad constraint values' % (self.__class__.__name__,) - ) - self.start, self.stop = values - if self.start > self.stop: - raise error.PyAsn1Error( - '%s: screwed constraint values (start > stop): %s > %s' % ( - self.__class__.__name__, - self.start, self.stop - ) - ) - AbstractConstraint._setValues(self, values) - - -class ValueSizeConstraint(ValueRangeConstraint): - """len(value) must be within start and stop values (inclusive)""" - - def _testValue(self, value, idx): - valueSize = len(value) - if valueSize < self.start or valueSize > self.stop: - raise error.ValueConstraintError(value) - - -class PermittedAlphabetConstraint(SingleValueConstraint): - def _setValues(self, values): - self._values = values - self._set = set(values) - - def _testValue(self, value, idx): - if not self._set.issuperset(value): - raise error.ValueConstraintError(value) - - -# This is a bit kludgy, meaning two op modes within a single constraint -class InnerTypeConstraint(AbstractConstraint): - """Value must satisfy type and presense constraints""" - - def _testValue(self, value, idx): - if self.__singleTypeConstraint: - self.__singleTypeConstraint(value) - elif self.__multipleTypeConstraint: - if idx not in self.__multipleTypeConstraint: - raise error.ValueConstraintError(value) - constraint, status = self.__multipleTypeConstraint[idx] - if status == 'ABSENT': # XXX presense is not checked! - raise error.ValueConstraintError(value) - constraint(value) - - def _setValues(self, values): - self.__multipleTypeConstraint = {} - self.__singleTypeConstraint = None - for v in values: - if isinstance(v, tuple): - self.__multipleTypeConstraint[v[0]] = v[1], v[2] - else: - self.__singleTypeConstraint = v - AbstractConstraint._setValues(self, values) - - -# Boolean ops on constraints - -class ConstraintsExclusion(AbstractConstraint): - """Value must not fit the single constraint""" - - def _testValue(self, value, idx): - try: - self._values[0](value, idx) - except error.ValueConstraintError: - return - else: - raise error.ValueConstraintError(value) - - def _setValues(self, values): - if len(values) != 1: - raise error.PyAsn1Error('Single constraint expected') - AbstractConstraint._setValues(self, values) - - -class AbstractConstraintSet(AbstractConstraint): - """Value must not satisfy the single constraint""" - - def __getitem__(self, idx): - return self._values[idx] - - def __iter__(self): - return iter(self._values) - - def __add__(self, value): - return self.__class__(*(self._values + (value,))) - - def __radd__(self, value): - return self.__class__(*((value,) + self._values)) - - def __len__(self): - return len(self._values) - - # Constraints inclusion in sets - - def _setValues(self, values): - self._values = values - for constraint in values: - if constraint: - self._valueMap.add(constraint) - self._valueMap.update(constraint.getValueMap()) - - -class ConstraintsIntersection(AbstractConstraintSet): - """Value must satisfy all constraints""" - - def _testValue(self, value, idx): - for constraint in self._values: - constraint(value, idx) - - -class ConstraintsUnion(AbstractConstraintSet): - """Value must satisfy at least one constraint""" - - def _testValue(self, value, idx): - for constraint in self._values: - try: - constraint(value, idx) - except error.ValueConstraintError: - pass - else: - return - raise error.ValueConstraintError( - 'all of %s failed for \"%s\"' % (self._values, value) - ) - -# XXX -# add tests for type check diff --git a/src/lib/pyasn1/type/error.py b/src/lib/pyasn1/type/error.py deleted file mode 100644 index cbfa276a..00000000 --- a/src/lib/pyasn1/type/error.py +++ /dev/null @@ -1,11 +0,0 @@ -# -# This file is part of pyasn1 software. -# -# Copyright (c) 2005-2017, Ilya Etingof -# License: http://pyasn1.sf.net/license.html -# -from pyasn1.error import PyAsn1Error - - -class ValueConstraintError(PyAsn1Error): - pass diff --git a/src/lib/pyasn1/type/namedtype.py b/src/lib/pyasn1/type/namedtype.py deleted file mode 100644 index 3f9ae190..00000000 --- a/src/lib/pyasn1/type/namedtype.py +++ /dev/null @@ -1,475 +0,0 @@ -# -# This file is part of pyasn1 software. -# -# Copyright (c) 2005-2017, Ilya Etingof -# License: http://pyasn1.sf.net/license.html -# -import sys -from pyasn1.type import tagmap -from pyasn1 import error - -__all__ = ['NamedType', 'OptionalNamedType', 'DefaultedNamedType', 'NamedTypes'] - - -class NamedType(object): - """Create named field object for a constructed ASN.1 type. - - The |NamedType| object represents a single name and ASN.1 type of a constructed ASN.1 type. - - |NamedType| objects are immutable and duck-type Python :class:`tuple` objects - holding *name* and *asn1Object* components. - - Parameters - ---------- - name: :py:class:`str` - Field name - - asn1Object: - ASN.1 type object - """ - isOptional = False - isDefaulted = False - - def __init__(self, name, asn1Object): - self.__name = name - self.__type = asn1Object - self.__nameAndType = name, asn1Object - - def __repr__(self): - return '%s(%r, %r)' % (self.__class__.__name__, self.__name, self.__type) - - def __eq__(self, other): - return self.__nameAndType == other - - def __ne__(self, other): - return self.__nameAndType != other - - def __lt__(self, other): - return self.__nameAndType < other - - def __le__(self, other): - return self.__nameAndType <= other - - def __gt__(self, other): - return self.__nameAndType > other - - def __ge__(self, other): - return self.__nameAndType >= other - - def __hash__(self): - return hash(self.__nameAndType) - - def __getitem__(self, idx): - return self.__nameAndType[idx] - - def __iter__(self): - return iter(self.__nameAndType) - - @property - def name(self): - return self.__name - - @property - def asn1Object(self): - return self.__type - - # Backward compatibility - - def getName(self): - return self.name - - def getType(self): - return self.asn1Object - - -class OptionalNamedType(NamedType): - __doc__ = NamedType.__doc__ - - isOptional = True - - -class DefaultedNamedType(NamedType): - __doc__ = NamedType.__doc__ - - isDefaulted = True - - -class NamedTypes(object): - """Create a collection of named fields for a constructed ASN.1 type. - - The NamedTypes object represents a collection of named fields of a constructed ASN.1 type. - - *NamedTypes* objects are immutable and duck-type Python :class:`dict` objects - holding *name* as keys and ASN.1 type object as values. - - Parameters - ---------- - *namedTypes: :class:`~pyasn1.type.namedtype.NamedType` - """ - def __init__(self, *namedTypes): - self.__namedTypes = namedTypes - self.__namedTypesLen = len(self.__namedTypes) - self.__minTagSet = None - self.__tagToPosMapImpl = None - self.__nameToPosMapImpl = None - self.__ambigiousTypesImpl = None - self.__tagMap = {} - self.__hasOptionalOrDefault = None - self.__requiredComponents = None - - def __repr__(self): - return '%s(%s)' % ( - self.__class__.__name__, ', '.join([repr(x) for x in self.__namedTypes]) - ) - - def __eq__(self, other): - return self.__namedTypes == other - - def __ne__(self, other): - return self.__namedTypes != other - - def __lt__(self, other): - return self.__namedTypes < other - - def __le__(self, other): - return self.__namedTypes <= other - - def __gt__(self, other): - return self.__namedTypes > other - - def __ge__(self, other): - return self.__namedTypes >= other - - def __hash__(self): - return hash(self.__namedTypes) - - def __getitem__(self, idx): - try: - return self.__namedTypes[idx] - - except TypeError: - return self.__namedTypes[self.__nameToPosMap[idx]] - - def __contains__(self, key): - return key in self.__nameToPosMap - - def __iter__(self): - return (x[0] for x in self.__namedTypes) - - if sys.version_info[0] <= 2: - def __nonzero__(self): - return self.__namedTypesLen > 0 - else: - def __bool__(self): - return self.__namedTypesLen > 0 - - def __len__(self): - return self.__namedTypesLen - - # Python dict protocol - - def values(self): - return (namedType.asn1Object for namedType in self.__namedTypes) - - def keys(self): - return (namedType.name for namedType in self.__namedTypes) - - def items(self): - return ((namedType.name, namedType.asn1Object) for namedType in self.__namedTypes) - - def clone(self): - return self.__class__(*self.__namedTypes) - - @property - def __tagToPosMap(self): - if self.__tagToPosMapImpl is None: - self.__tagToPosMapImpl = {} - for idx, namedType in enumerate(self.__namedTypes): - tagMap = namedType.asn1Object.tagMap - if not tagMap: - continue - for _tagSet in tagMap.presentTypes: - if _tagSet in self.__tagToPosMapImpl: - raise error.PyAsn1Error('Duplicate type %s in %s' % (_tagSet, namedType)) - self.__tagToPosMapImpl[_tagSet] = idx - - return self.__tagToPosMapImpl - - @property - def __nameToPosMap(self): - if self.__nameToPosMapImpl is None: - self.__nameToPosMapImpl = {} - for idx, namedType in enumerate(self.__namedTypes): - if namedType.name in self.__nameToPosMapImpl: - raise error.PyAsn1Error('Duplicate name %s in %s' % (namedType.name, namedType)) - self.__nameToPosMapImpl[namedType.name] = idx - - return self.__nameToPosMapImpl - - @property - def __ambigiousTypes(self): - if self.__ambigiousTypesImpl is None: - self.__ambigiousTypesImpl = {} - ambigiousTypes = () - for idx, namedType in reversed(tuple(enumerate(self.__namedTypes))): - if namedType.isOptional or namedType.isDefaulted: - ambigiousTypes = (namedType,) + ambigiousTypes - else: - ambigiousTypes = (namedType,) - self.__ambigiousTypesImpl[idx] = NamedTypes(*ambigiousTypes) - return self.__ambigiousTypesImpl - - def getTypeByPosition(self, idx): - """Return ASN.1 type object by its position in fields set. - - Parameters - ---------- - idx: :py:class:`int` - Field index - - Returns - ------- - : - ASN.1 type - - Raises - ------ - : :class:`~pyasn1.error.PyAsn1Error` - If given position is out of fields range - """ - try: - return self.__namedTypes[idx].asn1Object - - except IndexError: - raise error.PyAsn1Error('Type position out of range') - - def getPositionByType(self, tagSet): - """Return field position by its ASN.1 type. - - Parameters - ---------- - tagSet: :class:`~pysnmp.type.tag.TagSet` - ASN.1 tag set distinguishing one ASN.1 type from others. - - Returns - ------- - : :py:class:`int` - ASN.1 type position in fields set - - Raises - ------ - : :class:`~pyasn1.error.PyAsn1Error` - If *tagSet* is not present or ASN.1 types are not unique within callee *NamedTypes* - """ - try: - return self.__tagToPosMap[tagSet] - - except KeyError: - raise error.PyAsn1Error('Type %s not found' % (tagSet,)) - - def getNameByPosition(self, idx): - """Return field name by its position in fields set. - - Parameters - ---------- - idx: :py:class:`idx` - Field index - - Returns - ------- - : :py:class:`str` - Field name - - Raises - ------ - : :class:`~pyasn1.error.PyAsn1Error` - If given field name is not present in callee *NamedTypes* - """ - try: - return self.__namedTypes[idx].name - - except IndexError: - raise error.PyAsn1Error('Type position out of range') - - def getPositionByName(self, name): - """Return field position by filed name. - - Parameters - ---------- - name: :py:class:`str` - Field name - - Returns - ------- - : :py:class:`int` - Field position in fields set - - Raises - ------ - : :class:`~pyasn1.error.PyAsn1Error` - If *name* is not present or not unique within callee *NamedTypes* - """ - try: - return self.__nameToPosMap[name] - - except KeyError: - raise error.PyAsn1Error('Name %s not found' % (name,)) - - def getTagMapNearPosition(self, idx): - """Return ASN.1 types that are allowed at or past given field position. - - Some ASN.1 serialization allow for skipping optional and defaulted fields. - Some constructed ASN.1 types allow reordering of the fields. When recovering - such objects it may be important to know which types can possibly be - present at any given position in the field sets. - - Parameters - ---------- - idx: :py:class:`int` - Field index - - Returns - ------- - : :class:`~pyasn1.type.tagmap.TagMap` - Map if ASN.1 types allowed at given field position - - Raises - ------ - : :class:`~pyasn1.error.PyAsn1Error` - If given position is out of fields range - """ - try: - return self.__ambigiousTypes[idx].getTagMap() - - except KeyError: - raise error.PyAsn1Error('Type position out of range') - - def getPositionNearType(self, tagSet, idx): - """Return the closest field position where given ASN.1 type is allowed. - - Some ASN.1 serialization allow for skipping optional and defaulted fields. - Some constructed ASN.1 types allow reordering of the fields. When recovering - such objects it may be important to know at which field position, in field set, - given *tagSet* is allowed at or past *idx* position. - - Parameters - ---------- - tagSet: :class:`~pyasn1.type.tag.TagSet` - ASN.1 type which field position to look up - - idx: :py:class:`int` - Field position at or past which to perform ASN.1 type look up - - Returns - ------- - : :py:class:`int` - Field position in fields set - - Raises - ------ - : :class:`~pyasn1.error.PyAsn1Error` - If *tagSet* is not present or not unique within callee *NamedTypes* - or *idx* is out of fields range - """ - try: - return idx + self.__ambigiousTypes[idx].getPositionByType(tagSet) - - except KeyError: - raise error.PyAsn1Error('Type position out of range') - - @property - def minTagSet(self): - """Return the minimal TagSet among ASN.1 type in callee *NamedTypes*. - - Some ASN.1 types/serialization protocols require ASN.1 types to be - arranged based on their numerical tag value. The *minTagSet* property - returns that. - - Returns - ------- - : :class:`~pyasn1.type.tagset.TagSet` - Minimal TagSet among ASN.1 types in callee *NamedTypes* - """ - if self.__minTagSet is None: - for namedType in self.__namedTypes: - asn1Object = namedType.asn1Object - try: - tagSet = asn1Object.getMinTagSet() - - except AttributeError: - tagSet = asn1Object.tagSet - if self.__minTagSet is None or tagSet < self.__minTagSet: - self.__minTagSet = tagSet - return self.__minTagSet - - def getTagMap(self, unique=False): - """Create a *TagMap* object from tags and types recursively. - - Create a new :class:`~pyasn1.type.tagmap.TagMap` object by - combining tags from *TagMap* objects of children types and - associating them with their immediate child type. - - Example - ------- - - .. code-block:: python - - OuterType ::= CHOICE { - innerType INTEGER - } - - Calling *.getTagMap()* on *OuterType* will yield a map like this: - - .. code-block:: python - - Integer.tagSet -> Choice - - Parameters - ---------- - unique: :py:class:`bool` - If `True`, duplicate *TagSet* objects occurring while building - new *TagMap* would cause error. - - Returns - ------- - : :class:`~pyasn1.type.tagmap.TagMap` - New *TagMap* holding *TagSet* object gathered from childen types. - """ - if unique not in self.__tagMap: - presentTypes = {} - skipTypes = {} - defaultType = None - for namedType in self.__namedTypes: - tagMap = namedType.asn1Object.tagMap - for tagSet in tagMap: - if unique and tagSet in presentTypes: - raise error.PyAsn1Error('Non-unique tagSet %s' % (tagSet,)) - presentTypes[tagSet] = namedType.asn1Object - skipTypes.update(tagMap.skipTypes) - - if defaultType is None: - defaultType = tagMap.defaultType - elif tagMap.defaultType is not None: - raise error.PyAsn1Error('Duplicate default ASN.1 type at %s' % (self,)) - - self.__tagMap[unique] = tagmap.TagMap(presentTypes, skipTypes, defaultType) - - return self.__tagMap[unique] - - @property - def hasOptionalOrDefault(self): - if self.__hasOptionalOrDefault is None: - self.__hasOptionalOrDefault = bool([True for namedType in self.__namedTypes if namedType.isDefaulted or namedType.isOptional]) - return self.__hasOptionalOrDefault - - @property - def namedTypes(self): - return iter(self.__namedTypes) - - @property - def requiredComponents(self): - if self.__requiredComponents is None: - self.__requiredComponents = frozenset( - [idx for idx, nt in enumerate(self.__namedTypes) if not nt.isOptional and not nt.isDefaulted] - ) - return self.__requiredComponents diff --git a/src/lib/pyasn1/type/namedval.py b/src/lib/pyasn1/type/namedval.py deleted file mode 100644 index bcdbf153..00000000 --- a/src/lib/pyasn1/type/namedval.py +++ /dev/null @@ -1,94 +0,0 @@ -# -# This file is part of pyasn1 software. -# -# Copyright (c) 2005-2017, Ilya Etingof -# License: http://pyasn1.sf.net/license.html -# -# ASN.1 named integers -# -from pyasn1 import error - -__all__ = ['NamedValues'] - - -class NamedValues(object): - def __init__(self, *namedValues): - self.nameToValIdx = {} - self.valToNameIdx = {} - self.namedValues = () - automaticVal = 1 - for namedValue in namedValues: - if isinstance(namedValue, tuple): - name, val = namedValue - else: - name = namedValue - val = automaticVal - if name in self.nameToValIdx: - raise error.PyAsn1Error('Duplicate name %s' % (name,)) - self.nameToValIdx[name] = val - if val in self.valToNameIdx: - raise error.PyAsn1Error('Duplicate value %s=%s' % (name, val)) - self.valToNameIdx[val] = name - self.namedValues = self.namedValues + ((name, val),) - automaticVal += 1 - - def __repr__(self): - return '%s(%s)' % (self.__class__.__name__, ', '.join([repr(x) for x in self.namedValues])) - - def __str__(self): - return str(self.namedValues) - - def __eq__(self, other): - return tuple(self) == tuple(other) - - def __ne__(self, other): - return tuple(self) != tuple(other) - - def __lt__(self, other): - return tuple(self) < tuple(other) - - def __le__(self, other): - return tuple(self) <= tuple(other) - - def __gt__(self, other): - return tuple(self) > tuple(other) - - def __ge__(self, other): - return tuple(self) >= tuple(other) - - def __hash__(self): - return hash(tuple(self)) - - def getName(self, value): - if value in self.valToNameIdx: - return self.valToNameIdx[value] - - def getValue(self, name): - if name in self.nameToValIdx: - return self.nameToValIdx[name] - - def getValues(self, *names): - try: - return [self.nameToValIdx[name] for name in names] - - except KeyError: - raise error.PyAsn1Error( - 'Unknown bit identifier(s): %s' % (set(names).difference(self.nameToValIdx),) - ) - - def __getitem__(self, i): - return self.namedValues[i] - - def __len__(self): - return len(self.namedValues) - - def __add__(self, namedValues): - return self.__class__(*self.namedValues + namedValues) - - def __radd__(self, namedValues): - return self.__class__(*namedValues + tuple(self)) - - def clone(self, *namedValues): - return self.__class__(*tuple(self) + namedValues) - -# XXX clone/subtype? diff --git a/src/lib/pyasn1/type/tag.py b/src/lib/pyasn1/type/tag.py deleted file mode 100644 index aaf18572..00000000 --- a/src/lib/pyasn1/type/tag.py +++ /dev/null @@ -1,342 +0,0 @@ -# -# This file is part of pyasn1 software. -# -# Copyright (c) 2005-2017, Ilya Etingof -# License: http://pyasn1.sf.net/license.html -# -from pyasn1 import error - -__all__ = ['tagClassUniversal', 'tagClassApplication', 'tagClassContext', - 'tagClassPrivate', 'tagFormatSimple', 'tagFormatConstructed', - 'tagCategoryImplicit', 'tagCategoryExplicit', 'tagCategoryUntagged', - 'Tag', 'TagSet'] - -#: Identifier for ASN.1 class UNIVERSAL -tagClassUniversal = 0x00 - -#: Identifier for ASN.1 class APPLICATION -tagClassApplication = 0x40 - -#: Identifier for ASN.1 class context-specific -tagClassContext = 0x80 - -#: Identifier for ASN.1 class private -tagClassPrivate = 0xC0 - -#: Identifier for "simple" ASN.1 structure (e.g. scalar) -tagFormatSimple = 0x00 - -#: Identifier for "constructed" ASN.1 structure (e.g. may have inner components) -tagFormatConstructed = 0x20 - -tagCategoryImplicit = 0x01 -tagCategoryExplicit = 0x02 -tagCategoryUntagged = 0x04 - - -class Tag(object): - """Create ASN.1 tag - - Represents ASN.1 tag that can be attached to a ASN.1 type to make - types distinguishable from each other. - - *Tag* objects are immutable and duck-type Python :class:`tuple` objects - holding three integer components of a tag. - - Parameters - ---------- - tagClass: :py:class:`int` - Tag *class* value - - tagFormat: :py:class:`int` - Tag *format* value - - tagId: :py:class:`int` - Tag ID value - """ - def __init__(self, tagClass, tagFormat, tagId): - if tagId < 0: - raise error.PyAsn1Error('Negative tag ID (%s) not allowed' % tagId) - self.__tagClass = tagClass - self.__tagFormat = tagFormat - self.__tagId = tagId - self.__tagClassId = tagClass, tagId - self.__lazyHash = None - - def __str__(self): - return '[%s:%s:%s]' % (self.__tagClass, self.__tagFormat, self.__tagId) - - def __repr__(self): - return '%s(tagClass=%s, tagFormat=%s, tagId=%s)' % ( - (self.__class__.__name__, self.__tagClass, self.__tagFormat, self.__tagId) - ) - - def __eq__(self, other): - return self.__tagClassId == other - - def __ne__(self, other): - return self.__tagClassId != other - - def __lt__(self, other): - return self.__tagClassId < other - - def __le__(self, other): - return self.__tagClassId <= other - - def __gt__(self, other): - return self.__tagClassId > other - - def __ge__(self, other): - return self.__tagClassId >= other - - def __hash__(self): - if self.__lazyHash is None: - self.__lazyHash = hash(self.__tagClassId) - return self.__lazyHash - - def __getitem__(self, idx): - if idx == 0: - return self.__tagClass - elif idx == 1: - return self.__tagFormat - elif idx == 2: - return self.__tagId - else: - raise IndexError() - - def __iter__(self): - yield self.__tagClass - yield self.__tagFormat - yield self.__tagId - - def __and__(self, otherTag): - return self.__class__(self.__tagClass & otherTag.tagClass, - self.__tagFormat & otherTag.tagFormat, - self.__tagId & otherTag.tagId) - - def __or__(self, otherTag): - return self.__class__(self.__tagClass | otherTag.tagClass, - self.__tagFormat | otherTag.tagFormat, - self.__tagId | otherTag.tagId) - - @property - def tagClass(self): - """ASN.1 tag class - - Returns - ------- - : :py:class:`int` - Tag class - """ - return self.__tagClass - - @property - def tagFormat(self): - """ASN.1 tag format - - Returns - ------- - : :py:class:`int` - Tag format - """ - return self.__tagFormat - - @property - def tagId(self): - """ASN.1 tag ID - - Returns - ------- - : :py:class:`int` - Tag ID - """ - return self.__tagId - - -class TagSet(object): - """Create a collection of ASN.1 tags - - Represents a combination of :class:`~pyasn1.type.tag.Tag` objects - that can be attached to a ASN.1 type to make types distinguishable - from each other. - - *TagSet* objects are immutable and duck-type Python :class:`tuple` objects - holding arbitrary number of :class:`~pyasn1.type.tag.Tag` objects. - - Parameters - ---------- - baseTag: :class:`~pyasn1.type.tag.Tag` - Base *Tag* object. This tag survives IMPLICIT tagging. - - *superTags: :class:`~pyasn1.type.tag.Tag` - Additional *Tag* objects taking part in subtyping. - """ - def __init__(self, baseTag=(), *superTags): - self.__baseTag = baseTag - self.__superTags = superTags - self.__superTagsSignature = tuple( - [(superTag.tagClass, superTag.tagId) for superTag in superTags] - ) - self.__lenOfSuperTags = len(superTags) - self.__lazyHash = None - - def __str__(self): - return self.__superTags and '+'.join([str(x) for x in self.__superTags]) or '[untagged]' - - def __repr__(self): - return '%s(%s)' % ( - self.__class__.__name__, '(), ' + ', '.join([repr(x) for x in self.__superTags]) - ) - - def __add__(self, superTag): - return self.__class__(self.__baseTag, *self.__superTags + (superTag,)) - - def __radd__(self, superTag): - return self.__class__(self.__baseTag, *(superTag,) + self.__superTags) - - def __getitem__(self, i): - if i.__class__ is slice: - return self.__class__(self.__baseTag, *self.__superTags[i]) - else: - return self.__superTags[i] - - def __eq__(self, other): - return self.__superTagsSignature == other - - def __ne__(self, other): - return self.__superTagsSignature != other - - def __lt__(self, other): - return self.__superTagsSignature < other - - def __le__(self, other): - return self.__superTagsSignature <= other - - def __gt__(self, other): - return self.__superTagsSignature > other - - def __ge__(self, other): - return self.__superTagsSignature >= other - - def __hash__(self): - if self.__lazyHash is None: - self.__lazyHash = hash(self.__superTags) - return self.__lazyHash - - def __len__(self): - return self.__lenOfSuperTags - - # descriptor protocol - - def __get__(self, instance, owner): - if instance is None: - return self - - # This is a bit of hack: look up instance attribute first, - # then try class attribute if instance attribute with that - # name is not available. - # The rationale is to have `.tagSet` readable-writeable - # as a class attribute and read-only as instance attribute. - try: - return instance._tagSet - - except AttributeError: - return self - - def __set__(self, instance, value): - raise AttributeError('attribute is read-only') - - @property - def baseTag(self): - """Return base ASN.1 tag - - Returns - ------- - : :class:`~pyasn1.type.tag.Tag` - Base tag of this *TagSet* - """ - return self.__baseTag - - @property - def superTags(self): - """Return ASN.1 tags - - Returns - ------- - : :py:class:`tuple` - Tuple of :class:`~pyasn1.type.tag.Tag` objects that this *TagSet* contains - """ - return self.__superTags - - def tagExplicitly(self, superTag): - """Return explicitly tagged *TagSet* - - Create a new *TagSet* representing callee *TagSet* explicitly tagged - with passed tag(s). With explicit tagging mode, new tags are appended - to existing tag(s). - - Parameters - ---------- - superTag: :class:`~pyasn1.type.tag.Tag` - *Tag* object to tag this *TagSet* - - Returns - ------- - : :class:`~pyasn1.type.tag.TagSet` - New *TagSet* object - """ - if superTag.tagClass == tagClassUniversal: - raise error.PyAsn1Error('Can\'t tag with UNIVERSAL class tag') - if superTag.tagFormat != tagFormatConstructed: - superTag = Tag(superTag.tagClass, tagFormatConstructed, superTag.tagId) - return self + superTag - - def tagImplicitly(self, superTag): - """Return implicitly tagged *TagSet* - - Create a new *TagSet* representing callee *TagSet* implicitly tagged - with passed tag(s). With implicit tagging mode, new tag(s) replace the - last existing tag. - - Parameters - ---------- - superTag: :class:`~pyasn1.type.tag.Tag` - *Tag* object to tag this *TagSet* - - Returns - ------- - : :class:`~pyasn1.type.tag.TagSet` - New *TagSet* object - """ - if self.__superTags: - superTag = Tag(superTag.tagClass, self.__superTags[-1].tagFormat, superTag.tagId) - return self[:-1] + superTag - - def isSuperTagSetOf(self, tagSet): - """Test type relationship against given *TagSet* - - The callee is considered to be a supertype of given *TagSet* - tag-wise if all tags in *TagSet* are present in the callee and - they are in the same order. - - Parameters - ---------- - tagSet: :class:`~pyasn1.type.tag.TagSet` - *TagSet* object to evaluate against the callee - - Returns - ------- - : :py:class:`bool` - `True` if callee is a supertype of *tagSet* - """ - if len(tagSet) < self.__lenOfSuperTags: - return False - return self.__superTags == tagSet[:self.__lenOfSuperTags] - - # Backward compatibility - - def getBaseTag(self): - return self.__baseTag - -def initTagSet(tag): - return TagSet(tag, tag) diff --git a/src/lib/pyasn1/type/tagmap.py b/src/lib/pyasn1/type/tagmap.py deleted file mode 100644 index 8527f33d..00000000 --- a/src/lib/pyasn1/type/tagmap.py +++ /dev/null @@ -1,102 +0,0 @@ -# -# This file is part of pyasn1 software. -# -# Copyright (c) 2005-2017, Ilya Etingof -# License: http://pyasn1.sf.net/license.html -# -from pyasn1 import error - -__all__ = ['TagMap'] - - -class TagMap(object): - """Map *TagSet* objects to ASN.1 types - - Create an object mapping *TagSet* object to ASN.1 type. - - *TagMap* objects are immutable and duck-type read-only Python - :class:`dict` objects holding *TagSet* objects as keys and ASN.1 - type objects as values. - - Parameters - ---------- - presentTypes: :py:class:`dict` - Map of :class:`~pyasn1.type.tag.TagSet` to ASN.1 objects considered - as being unconditionally present in the *TagMap*. - - skipTypes: :py:class:`dict` - A collection of :class:`~pyasn1.type.tag.TagSet` objects considered - as absent in the *TagMap* even when *defaultType* is present. - - defaultType: ASN.1 type object - An ASN.1 type object callee *TagMap* returns for any *TagSet* key not present - in *presentTypes* (unless given key is present in *skipTypes*). - """ - def __init__(self, presentTypes=None, skipTypes=None, defaultType=None): - self.__presentTypes = presentTypes or {} - self.__skipTypes = skipTypes or {} - self.__defaultType = defaultType - - def __contains__(self, tagSet): - return (tagSet in self.__presentTypes or - self.__defaultType is not None and tagSet not in self.__skipTypes) - - def __getitem__(self, tagSet): - try: - return self.__presentTypes[tagSet] - except KeyError: - if self.__defaultType is None: - raise KeyError() - elif tagSet in self.__skipTypes: - raise error.PyAsn1Error('Key in negative map') - else: - return self.__defaultType - - def __iter__(self): - return iter(self.__presentTypes) - - def __repr__(self): - s = self.__class__.__name__ + '(' - if self.__presentTypes: - s += 'presentTypes=%r, ' % (self.__presentTypes,) - if self.__skipTypes: - s += 'skipTypes=%r, ' % (self.__skipTypes,) - if self.__defaultType is not None: - s += 'defaultType=%r' % (self.__defaultType,) - return s + ')' - - def __str__(self): - s = self.__class__.__name__ + ': ' - if self.__presentTypes: - s += 'presentTypes: %s, ' % ', '.join([x.prettyPrintType() for x in self.__presentTypes.values()]) - if self.__skipTypes: - s += 'skipTypes: %s, ' % ', '.join([x.prettyPrintType() for x in self.__skipTypes.values()]) - if self.__defaultType is not None: - s += 'defaultType: %s, ' % self.__defaultType.prettyPrintType() - return s - - @property - def presentTypes(self): - """Return *TagSet* to ASN.1 type map present in callee *TagMap*""" - return self.__presentTypes - - @property - def skipTypes(self): - """Return *TagSet* collection unconditionally absent in callee *TagMap*""" - return self.__skipTypes - - @property - def defaultType(self): - """Return default ASN.1 type being returned for any missing *TagSet*""" - return self.__defaultType - - # Backward compatibility - - def getPosMap(self): - return self.presentTypes - - def getNegMap(self): - return self.skipTypes - - def getDef(self): - return self.defaultType diff --git a/src/lib/pyasn1/type/univ.py b/src/lib/pyasn1/type/univ.py deleted file mode 100644 index 1a146e03..00000000 --- a/src/lib/pyasn1/type/univ.py +++ /dev/null @@ -1,2806 +0,0 @@ -# -# This file is part of pyasn1 software. -# -# Copyright (c) 2005-2017, Ilya Etingof -# License: http://pyasn1.sf.net/license.html -# -import sys -import math -from pyasn1.type import base, tag, constraint, namedtype, namedval, tagmap -from pyasn1.codec.ber import eoo -from pyasn1.compat import octets, integer, binary -from pyasn1 import error - -NoValue = base.NoValue -noValue = NoValue() - -__all__ = ['Integer', 'Boolean', 'BitString', 'OctetString', 'Null', - 'ObjectIdentifier', 'Real', 'Enumerated', 'SequenceOfAndSetOfBase', 'SequenceOf', - 'SetOf', 'SequenceAndSetBase', 'Sequence', 'Set', 'Choice', 'Any', - 'NoValue', 'noValue'] - -# "Simple" ASN.1 types (yet incomplete) - -class Integer(base.AbstractSimpleAsn1Item): - """Create |ASN.1| type or object. - - |ASN.1| objects are immutable and duck-type Python :class:`int` objects. - - Parameters - ---------- - value : :class:`int`, :class:`str` or |ASN.1| object - Python integer or string literal or |ASN.1| class instance. - - tagSet: :py:class:`~pyasn1.type.tag.TagSet` - Object representing non-default ASN.1 tag(s) - - subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` - Object representing non-default ASN.1 subtype constraint(s) - - namedValues: :py:class:`~pyasn1.type.namedval.NamedValues` - Object representing non-default symbolic aliases for numbers - - Raises - ------ - : :py:class:`pyasn1.error.PyAsn1Error` - On constraint violation or bad initializer. - """ - #: Set (class attribute) or return (class or instance attribute) a - #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) - #: associated with |ASN.1| type. - tagSet = tag.initTagSet( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x02) - ) - - #: Set (class attribute) or return (class or instance attribute) a - #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object - #: imposing constraints on |ASN.1| type initialization values. - subtypeSpec = constraint.ConstraintsIntersection() - - #: Default :py:class:`~pyasn1.type.namedval.NamedValues` object - #: representing symbolic aliases for numbers - namedValues = namedval.NamedValues() - - # Optimization for faster codec lookup - typeId = base.AbstractSimpleAsn1Item.getTypeId() - - def __init__(self, value=noValue, tagSet=None, subtypeSpec=None, - namedValues=None): - if namedValues is None: - self.__namedValues = self.namedValues - else: - self.__namedValues = namedValues - base.AbstractSimpleAsn1Item.__init__( - self, value, tagSet, subtypeSpec - ) - - def __repr__(self): - if self.__namedValues is not self.namedValues: - return '%s, %r)' % (base.AbstractSimpleAsn1Item.__repr__(self)[:-1], self.__namedValues) - else: - return base.AbstractSimpleAsn1Item.__repr__(self) - - def __and__(self, value): - return self.clone(self._value & value) - - def __rand__(self, value): - return self.clone(value & self._value) - - def __or__(self, value): - return self.clone(self._value | value) - - def __ror__(self, value): - return self.clone(value | self._value) - - def __xor__(self, value): - return self.clone(self._value ^ value) - - def __rxor__(self, value): - return self.clone(value ^ self._value) - - def __lshift__(self, value): - return self.clone(self._value << value) - - def __rshift__(self, value): - return self.clone(self._value >> value) - - def __add__(self, value): - return self.clone(self._value + value) - - def __radd__(self, value): - return self.clone(value + self._value) - - def __sub__(self, value): - return self.clone(self._value - value) - - def __rsub__(self, value): - return self.clone(value - self._value) - - def __mul__(self, value): - return self.clone(self._value * value) - - def __rmul__(self, value): - return self.clone(value * self._value) - - def __mod__(self, value): - return self.clone(self._value % value) - - def __rmod__(self, value): - return self.clone(value % self._value) - - def __pow__(self, value, modulo=None): - return self.clone(pow(self._value, value, modulo)) - - def __rpow__(self, value): - return self.clone(pow(value, self._value)) - - def __floordiv__(self, value): - return self.clone(self._value // value) - - def __rfloordiv__(self, value): - return self.clone(value // self._value) - - if sys.version_info[0] <= 2: - def __div__(self, value): - if isinstance(value, float): - return Real(self._value / value) - else: - return self.clone(self._value / value) - - def __rdiv__(self, value): - if isinstance(value, float): - return Real(value / self._value) - else: - return self.clone(value / self._value) - else: - def __truediv__(self, value): - return Real(self._value / value) - - def __rtruediv__(self, value): - return Real(value / self._value) - - def __divmod__(self, value): - return self.clone(divmod(self._value, value)) - - def __rdivmod__(self, value): - return self.clone(divmod(value, self._value)) - - __hash__ = base.AbstractSimpleAsn1Item.__hash__ - - def __int__(self): - return int(self._value) - - if sys.version_info[0] <= 2: - def __long__(self): return long(self._value) - - def __float__(self): - return float(self._value) - - def __abs__(self): - return self.clone(abs(self._value)) - - def __index__(self): - return int(self._value) - - def __pos__(self): - return self.clone(+self._value) - - def __neg__(self): - return self.clone(-self._value) - - def __invert__(self): - return self.clone(~self._value) - - def __round__(self, n=0): - r = round(self._value, n) - if n: - return self.clone(r) - else: - return r - - def __floor__(self): - return math.floor(self._value) - - def __ceil__(self): - return math.ceil(self._value) - - if sys.version_info[0:2] > (2, 5): - def __trunc__(self): - return self.clone(math.trunc(self._value)) - - def __lt__(self, value): - return self._value < value - - def __le__(self, value): - return self._value <= value - - def __eq__(self, value): - return self._value == value - - def __ne__(self, value): - return self._value != value - - def __gt__(self, value): - return self._value > value - - def __ge__(self, value): - return self._value >= value - - def prettyIn(self, value): - try: - return int(value) - - except ValueError: - valueOfName = self.__namedValues.getValue(value) - if valueOfName is not None: - return valueOfName - - raise error.PyAsn1Error( - 'Can\'t coerce %r into integer: %s' % (value, sys.exc_info()[1]) - ) - - def prettyOut(self, value): - nameOfValue = self.__namedValues.getName(value) - return nameOfValue is None and str(value) or repr(nameOfValue) - - def getNamedValues(self): - return self.__namedValues - - def clone(self, value=noValue, tagSet=None, subtypeSpec=None, namedValues=None): - """Create a copy of a |ASN.1| type or object. - - Any parameters to the *clone()* method will replace corresponding - properties of the |ASN.1| object. - - Parameters - ---------- - value: :class:`int`, :class:`str` or |ASN.1| object - Initialization value to pass to new ASN.1 object instead of - inheriting one from the caller. - - tagSet: :py:class:`~pyasn1.type.tag.TagSet` - Object representing ASN.1 tag(s) to use in new object instead of inheriting from the caller - - subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` - Object representing ASN.1 subtype constraint(s) to use in new object instead of inheriting from the caller - - namedValues: :py:class:`~pyasn1.type.namedval.NamedValues` - Object representing symbolic aliases for numbers to use instead of inheriting from caller - - Returns - ------- - : - new instance of |ASN.1| type/value - """ - isModified = False - - if value is None or value is noValue: - value = self._value - else: - isModified = True - if tagSet is None or tagSet is noValue: - tagSet = self._tagSet - else: - isModified = True - if subtypeSpec is None or subtypeSpec is noValue: - subtypeSpec = self._subtypeSpec - else: - isModified = True - if namedValues is None or namedValues is noValue: - namedValues = self.__namedValues - else: - isModified = True - - if isModified: - return self.__class__(value, tagSet, subtypeSpec, namedValues) - else: - return self - - def subtype(self, value=noValue, implicitTag=None, explicitTag=None, - subtypeSpec=None, namedValues=None): - """Create a copy of a |ASN.1| type or object. - - Any parameters to the *subtype()* method will be added to the corresponding - properties of the |ASN.1| object. - - Parameters - ---------- - value: :class:`int`, :class:`str` or |ASN.1| object - Initialization value to pass to new ASN.1 object instead of - inheriting one from the caller. - - implicitTag: :py:class:`~pyasn1.type.tag.Tag` - Implicitly apply given ASN.1 tag object to caller's - :py:class:`~pyasn1.type.tag.TagSet`, then use the result as - new object's ASN.1 tag(s). - - explicitTag: :py:class:`~pyasn1.type.tag.Tag` - Explicitly apply given ASN.1 tag object to caller's - :py:class:`~pyasn1.type.tag.TagSet`, then use the result as - new object's ASN.1 tag(s). - - subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` - Add ASN.1 constraints object to one of the caller, then - use the result as new object's ASN.1 constraints. - - namedValues: :py:class:`~pyasn1.type.namedval.NamedValues` - Add given object representing symbolic aliases for numbers - to one of the caller, then use the result as new object's - named numbers. - - Returns - ------- - : - new instance of |ASN.1| type/value - """ - isModified = False - - if value is None or value is noValue: - value = self._value - else: - isModified = True - if implicitTag is not None and implicitTag is not noValue: - tagSet = self._tagSet.tagImplicitly(implicitTag) - isModified = True - elif explicitTag is not None and explicitTag is not noValue: - tagSet = self._tagSet.tagExplicitly(explicitTag) - isModified = True - else: - tagSet = self._tagSet - if subtypeSpec is None or subtypeSpec is noValue: - subtypeSpec = self._subtypeSpec - else: - subtypeSpec = self._subtypeSpec + subtypeSpec - isModified = True - if namedValues is None or namedValues is noValue: - namedValues = self.__namedValues - else: - namedValues = namedValues + self.__namedValues - isModified = True - - if isModified: - return self.__class__(value, tagSet, subtypeSpec, namedValues) - else: - return self - - -class Boolean(Integer): - __doc__ = Integer.__doc__ - - #: Set (class attribute) or return (class or instance attribute) a - #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) - #: associated with |ASN.1| type. - tagSet = tag.initTagSet( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x01), - ) - - #: Set (class attribute) or return (class or instance attribute) a - #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object - #: imposing constraints on |ASN.1| type initialization values. - subtypeSpec = Integer.subtypeSpec + constraint.SingleValueConstraint(0, 1) - - #: Default :py:class:`~pyasn1.type.namedval.NamedValues` object - #: representing symbolic aliases for numbers - namedValues = Integer.namedValues.clone(('False', 0), ('True', 1)) - - # Optimization for faster codec lookup - typeId = Integer.getTypeId() - - -class BitString(base.AbstractSimpleAsn1Item): - """Create |ASN.1| type or object. - - |ASN.1| objects are immutable and duck-type both Python :class:`tuple` (as a tuple - of bits) and :class:`int` objects. - - Parameters - ---------- - value : :class:`int`, :class:`str` or |ASN.1| object - Python integer or string literal representing binary or hexadecimal - number or sequence of integer bits or |ASN.1| object. - - tagSet: :py:class:`~pyasn1.type.tag.TagSet` - Object representing non-default ASN.1 tag(s) - - subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` - Object representing non-default ASN.1 subtype constraint(s) - - namedValues: :py:class:`~pyasn1.type.namedval.NamedValues` - Object representing non-default symbolic aliases for numbers - - binValue: :py:class:`str` - Binary string initializer to use instead of the *value*. - Example: '10110011'. - - hexValue: :py:class:`str` - Hexadecimal string initializer to use instead of the *value*. - Example: 'DEADBEEF'. - - Raises - ------ - : :py:class:`pyasn1.error.PyAsn1Error` - On constraint violation or bad initializer. - """ - #: Set (class attribute) or return (class or instance attribute) a - #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) - #: associated with |ASN.1| type. - tagSet = tag.initTagSet( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x03) - ) - - #: Set (class attribute) or return (class or instance attribute) a - #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object - #: imposing constraints on |ASN.1| type initialization values. - subtypeSpec = constraint.ConstraintsIntersection() - - #: Default :py:class:`~pyasn1.type.namedval.NamedValues` object - #: representing symbolic aliases for numbers - namedValues = namedval.NamedValues() - - # Optimization for faster codec lookup - typeId = base.AbstractSimpleAsn1Item.getTypeId() - - defaultBinValue = defaultHexValue = noValue - - if sys.version_info[0] < 3: - SizedIntegerBase = long - else: - SizedIntegerBase = int - - class SizedInteger(SizedIntegerBase): - bitLength = leadingZeroBits = None - - def setBitLength(self, bitLength): - self.bitLength = bitLength - self.leadingZeroBits = max(bitLength - integer.bitLength(self), 0) - return self - - def __len__(self): - if self.bitLength is None: - self.setBitLength(integer.bitLength(self)) - - return self.bitLength - - def __init__(self, value=noValue, tagSet=None, subtypeSpec=None, - namedValues=None, binValue=noValue, hexValue=noValue): - if namedValues is None: - self.__namedValues = self.namedValues - else: - self.__namedValues = namedValues - if binValue is not noValue: - value = self.fromBinaryString(binValue) - elif hexValue is not noValue: - value = self.fromHexString(hexValue) - elif value is None or value is noValue: - if self.defaultBinValue is not noValue: - value = self.fromBinaryString(self.defaultBinValue) - elif self.defaultHexValue is not noValue: - value = self.fromHexString(self.defaultHexValue) - base.AbstractSimpleAsn1Item.__init__(self, value, tagSet, subtypeSpec) - - def clone(self, value=noValue, tagSet=None, subtypeSpec=None, - namedValues=None, binValue=noValue, hexValue=noValue): - """Create a copy of a |ASN.1| type or object. - - Any parameters to the *clone()* method will replace corresponding - properties of the |ASN.1| object. - - Parameters - ---------- - value : :class:`int`, :class:`str` or |ASN.1| object - Initialization value to pass to new ASN.1 object instead of - inheriting one from the caller. - - tagSet: :py:class:`~pyasn1.type.tag.TagSet` - Object representing ASN.1 tag(s) to use in new object instead of inheriting from the caller - - subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` - Object representing ASN.1 subtype constraint(s) to use in new object instead of inheriting from the caller - - namedValues: :py:class:`~pyasn1.type.namedval.NamedValues` - Class instance representing BitString type enumerations - - binValue: :py:class:`str` - Binary string initializer to use instead of the *value*. - Example: '10110011'. - - hexValue: :py:class:`str` - Hexadecimal string initializer to use instead of the *value*. - Example: 'DEADBEEF'. - - Returns - ------- - : - new instance of |ASN.1| type/value - """ - isModified = False - - if (value is None or value is noValue) and binValue is noValue and hexValue is noValue: - value = self._value - else: - isModified = True - if tagSet is None or tagSet is noValue: - tagSet = self._tagSet - else: - isModified = True - if subtypeSpec is None or subtypeSpec is noValue: - subtypeSpec = self._subtypeSpec - else: - isModified = True - if namedValues is None or namedValues is noValue: - namedValues = self.__namedValues - else: - isModified = True - - if isModified: - return self.__class__(value, tagSet, subtypeSpec, namedValues, binValue, hexValue) - else: - return self - - def subtype(self, value=noValue, implicitTag=None, explicitTag=None, - subtypeSpec=None, namedValues=None, binValue=noValue, hexValue=noValue): - """Create a copy of a |ASN.1| type or object. - - Any parameters to the *subtype()* method will be added to the corresponding - properties of the |ASN.1| object. - - Parameters - ---------- - value : :class:`int`, :class:`str` or |ASN.1| object - Initialization value to pass to new ASN.1 object instead of - inheriting one from the caller. - - implicitTag: :py:class:`~pyasn1.type.tag.Tag` - Implicitly apply given ASN.1 tag object to caller's - :py:class:`~pyasn1.type.tag.TagSet`, then use the result as - new object's ASN.1 tag(s). - - explicitTag: :py:class:`~pyasn1.type.tag.Tag` - Explicitly apply given ASN.1 tag object to caller's - :py:class:`~pyasn1.type.tag.TagSet`, then use the result as - new object's ASN.1 tag(s). - - subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` - Add ASN.1 constraints object to one of the caller, then - use the result as new object's ASN.1 constraints. - - namedValues: :py:class:`~pyasn1.type.namedval.NamedValues` - Add given object representing symbolic aliases for numbers - to one of the caller, then use the result as new object's - named numbers. - - binValue: :py:class:`str` - Binary string initializer to use instead of the *value*. - Example: '10110011'. - - hexValue: :py:class:`str` - Hexadecimal string initializer to use instead of the *value*. - Example: 'DEADBEEF'. - - Returns - ------- - : - new instance of |ASN.1| type/value - """ - isModified = False - - if (value is None or value is noValue) and binValue is noValue and hexValue is noValue: - value = self._value - else: - isModified = True - if implicitTag is not None and implicitTag is not noValue: - tagSet = self._tagSet.tagImplicitly(implicitTag) - isModified = True - elif explicitTag is not None and explicitTag is not noValue: - tagSet = self._tagSet.tagExplicitly(explicitTag) - isModified = True - else: - tagSet = self._tagSet - if subtypeSpec is None or subtypeSpec is noValue: - subtypeSpec = self._subtypeSpec - else: - subtypeSpec = self._subtypeSpec + subtypeSpec - isModified = True - if namedValues is None or namedValues is noValue: - namedValues = self.__namedValues - else: - namedValues = namedValues + self.__namedValues - isModified = True - - if isModified: - return self.__class__(value, tagSet, subtypeSpec, namedValues, binValue, hexValue) - else: - return self - - def __str__(self): - return self.asBinary() - - def __eq__(self, other): - other = self.prettyIn(other) - return self is other or self._value == other and len(self._value) == len(other) - - def __ne__(self, other): - other = self.prettyIn(other) - return self._value != other or len(self._value) != len(other) - - def __lt__(self, other): - other = self.prettyIn(other) - return len(self._value) < len(other) or len(self._value) == len(other) and self._value < other - - def __le__(self, other): - other = self.prettyIn(other) - return len(self._value) <= len(other) or len(self._value) == len(other) and self._value <= other - - def __gt__(self, other): - other = self.prettyIn(other) - return len(self._value) > len(other) or len(self._value) == len(other) and self._value > other - - def __ge__(self, other): - other = self.prettyIn(other) - return len(self._value) >= len(other) or len(self._value) == len(other) and self._value >= other - - # Immutable sequence object protocol - - def __len__(self): - return len(self._value) - - def __getitem__(self, i): - if i.__class__ is slice: - return self.clone([self[x] for x in range(*i.indices(len(self)))]) - else: - length = len(self._value) - 1 - if i > length or i < 0: - raise IndexError('bit index out of range') - return (self._value >> (length - i)) & 1 - - def __iter__(self): - length = len(self._value) - while length: - length -= 1 - yield (self._value >> length) & 1 - - def __reversed__(self): - return reversed(tuple(self)) - - # arithmetic operators - - def __add__(self, value): - value = self.prettyIn(value) - return self.clone(self.SizedInteger(self._value << len(value) | value).setBitLength(len(self._value) + len(value))) - - def __radd__(self, value): - value = self.prettyIn(value) - return self.clone(self.SizedInteger(value << len(self._value) | self._value).setBitLength(len(self._value) + len(value))) - - def __mul__(self, value): - bitString = self._value - while value > 1: - bitString <<= len(self._value) - bitString |= self._value - value -= 1 - return self.clone(bitString) - - def __rmul__(self, value): - return self * value - - def __lshift__(self, count): - return self.clone(self.SizedInteger(self._value << count).setBitLength(len(self._value) + count)) - - def __rshift__(self, count): - return self.clone(self.SizedInteger(self._value >> count).setBitLength(max(0, len(self._value) - count))) - - def __int__(self): - return self._value - - def __float__(self): - return float(self._value) - - if sys.version_info[0] < 3: - def __long__(self): - return self._value - - def asNumbers(self): - """Get |ASN.1| value as a sequence of 8-bit integers. - - If |ASN.1| object length is not a multiple of 8, result - will be left-padded with zeros. - """ - return tuple(octets.octs2ints(self.asOctets())) - - def asOctets(self): - """Get |ASN.1| value as a sequence of octets. - - If |ASN.1| object length is not a multiple of 8, result - will be left-padded with zeros. - """ - return integer.to_bytes(self._value, length=len(self)) - - def asInteger(self): - """Get |ASN.1| value as a single integer value. - """ - return self._value - - def asBinary(self): - """Get |ASN.1| value as a text string of bits. - """ - binString = binary.bin(self._value)[2:] - return '0'*(len(self._value) - len(binString)) + binString - - @classmethod - def fromHexString(cls, value): - try: - return cls.SizedInteger(value, 16).setBitLength(len(value) * 4) - - except ValueError: - raise error.PyAsn1Error('%s.fromHexString() error: %s' % (cls.__name__, sys.exc_info()[1])) - - @classmethod - def fromBinaryString(cls, value): - try: - return cls.SizedInteger(value or '0', 2).setBitLength(len(value)) - - except ValueError: - raise error.PyAsn1Error('%s.fromBinaryString() error: %s' % (cls.__name__, sys.exc_info()[1])) - - @classmethod - def fromOctetString(cls, value, padding=0): - return cls(cls.SizedInteger(integer.from_bytes(value) >> padding).setBitLength(len(value) * 8 - padding)) - - def prettyIn(self, value): - if octets.isStringType(value): - if not value: - return self.SizedInteger(0).setBitLength(0) - - elif value[0] == '\'': # "'1011'B" -- ASN.1 schema representation (deprecated) - if value[-2:] == '\'B': - return self.fromBinaryString(value[1:-2]) - elif value[-2:] == '\'H': - return self.fromHexString(value[1:-2]) - else: - raise error.PyAsn1Error( - 'Bad BIT STRING value notation %s' % (value,) - ) - - elif self.__namedValues and not value.isdigit(): # named bits like 'Urgent, Active' - bitPositions = self.__namedValues.getValues(*[x.strip() for x in value.split(',')]) - - rightmostPosition = max(bitPositions) - - number = 0 - for bitPosition in bitPositions: - number |= 1 << (rightmostPosition - bitPosition) - - return self.SizedInteger(number).setBitLength(rightmostPosition + 1) - - elif value.startswith('0x'): - return self.fromHexString(value[2:]) - - elif value.startswith('0b'): - return self.fromBinaryString(value[2:]) - - else: # assume plain binary string like '1011' - return self.fromBinaryString(value) - - elif isinstance(value, (tuple, list)): - return self.fromBinaryString(''.join([b and '1' or '0' for b in value])) - - elif isinstance(value, (self.SizedInteger, BitString)): - return self.SizedInteger(value).setBitLength(len(value)) - - elif isinstance(value, intTypes): - return self.SizedInteger(value) - - else: - raise error.PyAsn1Error( - 'Bad BitString initializer type \'%s\'' % (value,) - ) - - def prettyOut(self, value): - return '\'%s\'' % str(self) - - -try: - # noinspection PyStatementEffect - all - -except NameError: # Python 2.4 - # noinspection PyShadowingBuiltins - def all(iterable): - for element in iterable: - if not element: - return False - return True - - -class OctetString(base.AbstractSimpleAsn1Item): - """Create |ASN.1| type or object. - - |ASN.1| objects are immutable and duck-type Python 2 :class:`str` or Python 3 :class:`bytes`. - When used in Unicode context, |ASN.1| type assumes "|encoding|" serialization. - - Parameters - ---------- - value : :class:`str`, :class:`bytes` or |ASN.1| object - string (Python 2) or bytes (Python 3), alternatively unicode object - (Python 2) or string (Python 3) representing character string to be - serialized into octets (note `encoding` parameter) or |ASN.1| object. - - tagSet: :py:class:`~pyasn1.type.tag.TagSet` - Object representing non-default ASN.1 tag(s) - - subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` - Object representing non-default ASN.1 subtype constraint(s) - - encoding: :py:class:`str` - Unicode codec ID to encode/decode :class:`unicode` (Python 2) or - :class:`str` (Python 3) the payload when |ASN.1| object is used - in text string context. - - binValue: :py:class:`str` - Binary string initializer to use instead of the *value*. - Example: '10110011'. - - hexValue: :py:class:`str` - Hexadecimal string initializer to use instead of the *value*. - Example: 'DEADBEEF'. - - Raises - ------ - : :py:class:`pyasn1.error.PyAsn1Error` - On constraint violation or bad initializer. - """ - #: Set (class attribute) or return (class or instance attribute) a - #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) - #: associated with |ASN.1| type. - tagSet = tag.initTagSet( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x04) - ) - - #: Set (class attribute) or return (class or instance attribute) a - #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object - #: imposing constraints on |ASN.1| type initialization values. - subtypeSpec = constraint.ConstraintsIntersection() - - # Optimization for faster codec lookup - typeId = base.AbstractSimpleAsn1Item.getTypeId() - - defaultBinValue = defaultHexValue = noValue - encoding = 'iso-8859-1' - - def __init__(self, value=noValue, tagSet=None, subtypeSpec=None, - encoding=None, binValue=noValue, hexValue=noValue): - if encoding is None: - self._encoding = self.encoding - else: - self._encoding = encoding - if binValue is not noValue: - value = self.fromBinaryString(binValue) - elif hexValue is not noValue: - value = self.fromHexString(hexValue) - elif value is None or value is noValue: - if self.defaultBinValue is not noValue: - value = self.fromBinaryString(self.defaultBinValue) - elif self.defaultHexValue is not noValue: - value = self.fromHexString(self.defaultHexValue) - self.__asNumbersCache = None - base.AbstractSimpleAsn1Item.__init__(self, value, tagSet, subtypeSpec) - - def clone(self, value=noValue, tagSet=None, subtypeSpec=None, - encoding=None, binValue=noValue, hexValue=noValue): - """Create a copy of a |ASN.1| type or object. - - Any parameters to the *clone()* method will replace corresponding - properties of the |ASN.1| object. - - Parameters - ---------- - value : :class:`str`, :class:`bytes` or |ASN.1| object - Initialization value to pass to new ASN.1 object instead of - inheriting one from the caller. - - tagSet: :py:class:`~pyasn1.type.tag.TagSet` - Object representing ASN.1 tag(s) to use in new object instead of inheriting from the caller - - subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` - Object representing ASN.1 subtype constraint(s) to use in new object instead of inheriting from the caller - - encoding: :py:class:`str` - Unicode codec ID to encode/decode :class:`unicode` (Python 2) - or :class:`str` (Python 3) the payload when |ASN.1| - object is used in string context. - - binValue: :py:class:`str` - Binary string initializer. Example: '10110011'. - - hexValue: :py:class:`str` - Hexadecimal string initializer. Example: 'DEADBEEF'. - - Returns - ------- - : - new instance of |ASN.1| type/value - """ - isModified = False - - if (value is None or value is noValue) and binValue is noValue and hexValue is noValue: - value = self._value - else: - isModified = True - if tagSet is None or tagSet is noValue: - tagSet = self._tagSet - else: - isModified = True - if subtypeSpec is None or subtypeSpec is noValue: - subtypeSpec = self._subtypeSpec - else: - isModified = True - if encoding is None or encoding is noValue: - encoding = self._encoding - else: - isModified = True - - if isModified: - return self.__class__(value, tagSet, subtypeSpec, encoding, binValue, hexValue) - else: - return self - - def subtype(self, value=noValue, implicitTag=None, explicitTag=None, - subtypeSpec=None, encoding=None, binValue=noValue, - hexValue=noValue): - """Create a copy of a |ASN.1| type or object. - - Any parameters to the *subtype()* method will be added to the corresponding - properties of the |ASN.1| object. - - Parameters - ---------- - value : :class:`str`, :class:`bytes` or |ASN.1| object - Initialization value to pass to new ASN.1 object instead of - inheriting one from the caller. - - implicitTag: :py:class:`~pyasn1.type.tag.Tag` - Implicitly apply given ASN.1 tag object to |ASN.1| object tag set - :py:class:`~pyasn1.type.tag.TagSet`, then use the result as - new object's ASN.1 tag(s). - - explicitTag: :py:class:`~pyasn1.type.tag.Tag` - Explicitly apply given ASN.1 tag object to |ASN.1| object tag set - :py:class:`~pyasn1.type.tag.TagSet`, then use the result as - new object's ASN.1 tag(s). - - subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` - Add ASN.1 constraints object to one of the caller, then - use the result as new object's ASN.1 constraints. - - encoding: :py:class:`str` - Unicode codec ID to encode/decode :class:`unicode` (Python 2) - or :class:`str` (Python 3) the payload when *OctetString* - object is used in string context. - - binValue: :py:class:`str` - Binary string initializer. Example: '10110011'. - - hexValue: :py:class:`str` - Hexadecimal string initializer. Example: 'DEADBEEF'. - - Returns - ------- - : - new instance of |ASN.1| type/value - """ - isModified = False - - if (value is None or value is noValue) and binValue is noValue and hexValue is noValue: - value = self._value - else: - isModified = True - if implicitTag is not None and implicitTag is not noValue: - tagSet = self._tagSet.tagImplicitly(implicitTag) - isModified = True - elif explicitTag is not None and explicitTag is not noValue: - tagSet = self._tagSet.tagExplicitly(explicitTag) - isModified = True - else: - tagSet = self._tagSet - if subtypeSpec is None or subtypeSpec is noValue: - subtypeSpec = self._subtypeSpec - else: - subtypeSpec = self._subtypeSpec + subtypeSpec - isModified = True - if encoding is None or encoding is noValue: - encoding = self._encoding - else: - isModified = True - - if isModified: - return self.__class__(value, tagSet, subtypeSpec, encoding, binValue, hexValue) - else: - return self - - if sys.version_info[0] <= 2: - def prettyIn(self, value): - if isinstance(value, str): - return value - elif isinstance(value, unicode): - try: - return value.encode(self._encoding) - except (LookupError, UnicodeEncodeError): - raise error.PyAsn1Error( - 'Can\'t encode string \'%s\' with \'%s\' codec' % (value, self._encoding) - ) - elif isinstance(value, (tuple, list)): - try: - return ''.join([chr(x) for x in value]) - except ValueError: - raise error.PyAsn1Error( - 'Bad %s initializer \'%s\'' % (self.__class__.__name__, value) - ) - else: - return str(value) - - def __str__(self): - return str(self._value) - - def __unicode__(self): - try: - return self._value.decode(self._encoding) - - except UnicodeDecodeError: - raise error.PyAsn1Error( - 'Can\'t decode string \'%s\' with \'%s\' codec' % (self._value, self._encoding) - ) - - def asOctets(self): - return str(self._value) - - def asNumbers(self): - if self.__asNumbersCache is None: - self.__asNumbersCache = tuple([ord(x) for x in self._value]) - return self.__asNumbersCache - - else: - def prettyIn(self, value): - if isinstance(value, bytes): - return value - elif isinstance(value, str): - try: - return value.encode(self._encoding) - except UnicodeEncodeError: - raise error.PyAsn1Error( - 'Can\'t encode string \'%s\' with \'%s\' codec' % (value, self._encoding) - ) - elif isinstance(value, OctetString): # a shortcut, bytes() would work the same way - return value.asOctets() - elif isinstance(value, base.AbstractSimpleAsn1Item): # this mostly targets Integer objects - return self.prettyIn(str(value)) - elif isinstance(value, (tuple, list)): - return self.prettyIn(bytes(value)) - else: - return bytes(value) - - def __str__(self): - try: - return self._value.decode(self._encoding) - - except UnicodeDecodeError: - raise error.PyAsn1Error( - 'Can\'t decode string \'%s\' with \'%s\' codec at \'%s\'' % (self._value, self._encoding, self.__class__.__name__) - ) - - def __bytes__(self): - return bytes(self._value) - - def asOctets(self): - return bytes(self._value) - - def asNumbers(self): - if self.__asNumbersCache is None: - self.__asNumbersCache = tuple(self._value) - return self.__asNumbersCache - - def prettyOut(self, value): - if sys.version_info[0] <= 2: - numbers = tuple((ord(x) for x in value)) - else: - numbers = tuple(value) - for x in numbers: - if x < 32 or x > 126: - return '0x' + ''.join(('%.2x' % x for x in numbers)) - else: - return octets.octs2str(value) - - @staticmethod - def fromBinaryString(value): - bitNo = 8 - byte = 0 - r = [] - for v in value: - if bitNo: - bitNo -= 1 - else: - bitNo = 7 - r.append(byte) - byte = 0 - if v in ('0', '1'): - v = int(v) - else: - raise error.PyAsn1Error( - 'Non-binary OCTET STRING initializer %s' % (v,) - ) - byte |= v << bitNo - - r.append(byte) - - return octets.ints2octs(r) - - @staticmethod - def fromHexString(value): - r = [] - p = [] - for v in value: - if p: - r.append(int(p + v, 16)) - p = None - else: - p = v - if p: - r.append(int(p + '0', 16)) - - return octets.ints2octs(r) - - def __repr__(self): - r = [] - doHex = False - if self._value is not self.defaultValue: - for x in self.asNumbers(): - if x < 32 or x > 126: - doHex = True - break - if not doHex: - r.append('%r' % (self._value,)) - if self._tagSet is not self.__class__.tagSet: - r.append('tagSet=%r' % (self._tagSet,)) - if self._subtypeSpec is not self.subtypeSpec: - r.append('subtypeSpec=%r' % (self._subtypeSpec,)) - if self.encoding is not self._encoding: - r.append('encoding=%r' % (self._encoding,)) - if doHex: - r.append('hexValue=%r' % ''.join(['%.2x' % x for x in self.asNumbers()])) - return '%s(%s)' % (self.__class__.__name__, ', '.join(r)) - - # Immutable sequence object protocol - - def __len__(self): - if self._len is None: - self._len = len(self._value) - return self._len - - def __getitem__(self, i): - if i.__class__ is slice: - return self.clone(self._value[i]) - else: - return self._value[i] - - def __iter__(self): - return iter(self._value) - - def __contains__(self, value): - return value in self._value - - def __add__(self, value): - return self.clone(self._value + self.prettyIn(value)) - - def __radd__(self, value): - return self.clone(self.prettyIn(value) + self._value) - - def __mul__(self, value): - return self.clone(self._value * value) - - def __rmul__(self, value): - return self * value - - def __int__(self): - return int(self._value) - - def __float__(self): - return float(self._value) - - def __reversed__(self): - return reversed(self._value) - - -class Null(OctetString): - """Create |ASN.1| type or object. - - |ASN.1| objects are immutable and duck-type Python :class:`str` objects (always empty). - - Parameters - ---------- - value : :class:`str` or :py:class:`~pyasn1.type.univ.Null` object - Python empty string literal or *Null* class instance. - - tagSet: :py:class:`~pyasn1.type.tag.TagSet` - Object representing non-default ASN.1 tag(s) - - Raises - ------ - : :py:class:`pyasn1.error.PyAsn1Error` - On constraint violation or bad initializer. - """ - defaultValue = ''.encode() # This is tightly constrained - - #: Set (class attribute) or return (class or instance attribute) a - #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) - #: associated with |ASN.1| type. - tagSet = tag.initTagSet( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x05) - ) - subtypeSpec = OctetString.subtypeSpec + constraint.SingleValueConstraint(octets.str2octs('')) - - # Optimization for faster codec lookup - typeId = OctetString.getTypeId() - - def clone(self, value=noValue, tagSet=None): - """Create a copy of a |ASN.1| type or object. - - Any parameters to the *clone()* method will replace corresponding - properties of the |ASN.1| object. - - Parameters - ---------- - value: :class:`str` or |ASN.1| object - Initialization value to pass to new ASN.1 object instead of - inheriting one from the caller. - - tagSet: :py:class:`~pyasn1.type.tag.TagSet` - Object representing ASN.1 tag(s) to use in new object instead of inheriting from the caller - - Returns - ------- - : :py:class:`~pyasn1.type.univ.Null` - new instance of NULL type/value - """ - return OctetString.clone(self, value, tagSet) - - def subtype(self, value=noValue, implicitTag=None, explicitTag=None): - """Create a copy of a |ASN.1| type or object. - - Any parameters to the *subtype()* method will be added to the corresponding - properties of the |ASN.1| object. - - Parameters - ---------- - value: :class:`int`, :class:`str` or |ASN.1| object - Initialization value to pass to new ASN.1 object instead of - inheriting one from the caller. - - implicitTag: :py:class:`~pyasn1.type.tag.Tag` - Implicitly apply given ASN.1 tag object to caller's - :py:class:`~pyasn1.type.tag.TagSet`, then use the result as - new object's ASN.1 tag(s). - - explicitTag: :py:class:`~pyasn1.type.tag.Tag` - Explicitly apply given ASN.1 tag object to caller's - :py:class:`~pyasn1.type.tag.TagSet`, then use the result as - new object's ASN.1 tag(s). - - Returns - ------- - : :py:class:`~pyasn1.type.univ.Null` - new instance of NULL type/value - """ - return OctetString.subtype(self, value, implicitTag, explicitTag) - - -if sys.version_info[0] <= 2: - intTypes = (int, long) -else: - intTypes = (int,) - -numericTypes = intTypes + (float,) - - -class ObjectIdentifier(base.AbstractSimpleAsn1Item): - """Create |ASN.1| type or object. - - |ASN.1| objects are immutable and duck-type Python :class:`tuple` objects (tuple of non-negative integers). - - Parameters - ---------- - value: :class:`tuple`, :class:`str` or |ASN.1| object - Python sequence of :class:`int` or string literal or |ASN.1| object. - - tagSet: :py:class:`~pyasn1.type.tag.TagSet` - Object representing non-default ASN.1 tag(s) - - subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` - Object representing non-default ASN.1 subtype constraint(s) - - Raises - ------ - : :py:class:`pyasn1.error.PyAsn1Error` - On constraint violation or bad initializer. - """ - #: Set (class attribute) or return (class or instance attribute) a - #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) - #: associated with |ASN.1| type. - tagSet = tag.initTagSet( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x06) - ) - - #: Set (class attribute) or return (class or instance attribute) a - #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object - #: imposing constraints on |ASN.1| type initialization values. - subtypeSpec = constraint.ConstraintsIntersection() - - # Optimization for faster codec lookup - typeId = base.AbstractSimpleAsn1Item.getTypeId() - - def __add__(self, other): - return self.clone(self._value + other) - - def __radd__(self, other): - return self.clone(other + self._value) - - def asTuple(self): - return self._value - - # Sequence object protocol - - def __len__(self): - if self._len is None: - self._len = len(self._value) - return self._len - - def __getitem__(self, i): - if i.__class__ is slice: - return self.clone(self._value[i]) - else: - return self._value[i] - - def __iter__(self): - return iter(self._value) - - def __contains__(self, value): - return value in self._value - - def __str__(self): - return self.prettyPrint() - - def __repr__(self): - return '%s(%r)' % (self.__class__.__name__, self.prettyPrint()) - - def index(self, suboid): - return self._value.index(suboid) - - def isPrefixOf(self, other): - """Indicate if this |ASN.1| object is a prefix of other |ASN.1| object. - - Parameters - ---------- - other: |ASN.1| object - |ASN.1| object - - Returns - ------- - : :class:`bool` - :class:`True` if this |ASN.1| object is a parent (e.g. prefix) of the other |ASN.1| object - or :class:`False` otherwise. - """ - l = len(self) - if l <= len(other): - if self._value[:l] == other[:l]: - return True - return False - - def prettyIn(self, value): - if isinstance(value, ObjectIdentifier): - return tuple(value) - elif octets.isStringType(value): - if '-' in value: - raise error.PyAsn1Error( - 'Malformed Object ID %s at %s: %s' % (value, self.__class__.__name__, sys.exc_info()[1]) - ) - try: - return tuple([int(subOid) for subOid in value.split('.') if subOid]) - except ValueError: - raise error.PyAsn1Error( - 'Malformed Object ID %s at %s: %s' % (value, self.__class__.__name__, sys.exc_info()[1]) - ) - - try: - tupleOfInts = tuple([int(subOid) for subOid in value if subOid >= 0]) - - except (ValueError, TypeError): - raise error.PyAsn1Error( - 'Malformed Object ID %s at %s: %s' % (value, self.__class__.__name__, sys.exc_info()[1]) - ) - - if len(tupleOfInts) == len(value): - return tupleOfInts - - raise error.PyAsn1Error('Malformed Object ID %s at %s' % (value, self.__class__.__name__)) - - def prettyOut(self, value): - return '.'.join([str(x) for x in value]) - - -class Real(base.AbstractSimpleAsn1Item): - """Create |ASN.1| type or object. - - |ASN.1| objects are immutable and duck-type Python :class:`float` objects. - Additionally, |ASN.1| objects behave like a :class:`tuple` in which case its - elements are mantissa, base and exponent. - - Parameters - ---------- - value: :class:`tuple`, :class:`float` or |ASN.1| object - Python sequence of :class:`int` (representing mantissa, base and - exponent) or float instance or *Real* class instance. - - tagSet: :py:class:`~pyasn1.type.tag.TagSet` - Object representing non-default ASN.1 tag(s) - - subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` - Object representing non-default ASN.1 subtype constraint(s) - - Raises - ------ - : :py:class:`pyasn1.error.PyAsn1Error` - On constraint violation or bad initializer. - - """ - binEncBase = None # binEncBase = 16 is recommended for large numbers - - try: - _plusInf = float('inf') - _minusInf = float('-inf') - _inf = (_plusInf, _minusInf) - except ValueError: - # Infinity support is platform and Python dependent - _plusInf = _minusInf = None - _inf = () - - #: Set (class attribute) or return (class or instance attribute) a - #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) - #: associated with |ASN.1| type. - tagSet = tag.initTagSet( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x09) - ) - - #: Set (class attribute) or return (class or instance attribute) a - #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object - #: imposing constraints on |ASN.1| type initialization values. - subtypeSpec = constraint.ConstraintsIntersection() - - # Optimization for faster codec lookup - typeId = base.AbstractSimpleAsn1Item.getTypeId() - - def clone(self, value=noValue, tagSet=None, subtypeSpec=None): - """Create a copy of a |ASN.1| type or object. - - Any parameters to the *clone()* method will replace corresponding - properties of the |ASN.1| object. - - Parameters - ---------- - value: :class:`tuple`, :class:`float` or |ASN.1| object - Initialization value to pass to new ASN.1 object instead of - inheriting one from the caller. - - tagSet: :py:class:`~pyasn1.type.tag.TagSet` - Object representing ASN.1 tag(s) to use in new object instead of inheriting from the caller - - subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` - Object representing ASN.1 subtype constraint(s) to use in new object instead of inheriting from the caller - - Returns - ------- - : - new instance of |ASN.1| type/value - """ - return base.AbstractSimpleAsn1Item.clone(self, value, tagSet, subtypeSpec) - - def subtype(self, value=noValue, implicitTag=None, explicitTag=None, - subtypeSpec=None): - """Create a copy of a |ASN.1| type or object. - - Any parameters to the *subtype()* method will be added to the corresponding - properties of the |ASN.1| object. - - Parameters - ---------- - value: :class:`tuple`, :class:`float` or |ASN.1| object - Initialization value to pass to new ASN.1 object instead of - inheriting one from the caller. - - implicitTag: :py:class:`~pyasn1.type.tag.Tag` - Implicitly apply given ASN.1 tag object to caller's - :py:class:`~pyasn1.type.tag.TagSet`, then use the result as - new object's ASN.1 tag(s). - - explicitTag: :py:class:`~pyasn1.type.tag.Tag` - Explicitly apply given ASN.1 tag object to caller's - :py:class:`~pyasn1.type.tag.TagSet`, then use the result as - new object's ASN.1 tag(s). - - subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` - Object representing ASN.1 subtype constraint(s) to use in new object instead of inheriting from the caller - - Returns - ------- - : - new instance of |ASN.1| type/value - """ - return base.AbstractSimpleAsn1Item.subtype(self, value, implicitTag, explicitTag) - - @staticmethod - def __normalizeBase10(value): - m, b, e = value - while m and m % 10 == 0: - m /= 10 - e += 1 - return m, b, e - - def prettyIn(self, value): - if isinstance(value, tuple) and len(value) == 3: - if not isinstance(value[0], numericTypes) or \ - not isinstance(value[1], intTypes) or \ - not isinstance(value[2], intTypes): - raise error.PyAsn1Error('Lame Real value syntax: %s' % (value,)) - if isinstance(value[0], float) and \ - self._inf and value[0] in self._inf: - return value[0] - if value[1] not in (2, 10): - raise error.PyAsn1Error( - 'Prohibited base for Real value: %s' % (value[1],) - ) - if value[1] == 10: - value = self.__normalizeBase10(value) - return value - elif isinstance(value, intTypes): - return self.__normalizeBase10((value, 10, 0)) - elif isinstance(value, float) or octets.isStringType(value): - if octets.isStringType(value): - try: - value = float(value) - except ValueError: - raise error.PyAsn1Error( - 'Bad real value syntax: %s' % (value,) - ) - if self._inf and value in self._inf: - return value - else: - e = 0 - while int(value) != value: - value *= 10 - e -= 1 - return self.__normalizeBase10((int(value), 10, e)) - elif isinstance(value, Real): - return tuple(value) - raise error.PyAsn1Error( - 'Bad real value syntax: %s' % (value,) - ) - - def prettyOut(self, value): - if value in self._inf: - return '\'%s\'' % value - else: - return str(value) - - def prettyPrint(self, scope=0): - if self.isInfinity(): - return self.prettyOut(self._value) - else: - return str(float(self)) - - def isPlusInfinity(self): - """Indicate PLUS-INFINITY object value - - Returns - ------- - : :class:`bool` - :class:`True` if calling object represents plus infinity - or :class:`False` otherwise. - - """ - return self._value == self._plusInf - - def isMinusInfinity(self): - """Indicate MINUS-INFINITY object value - - Returns - ------- - : :class:`bool` - :class:`True` if calling object represents minus infinity - or :class:`False` otherwise. - """ - return self._value == self._minusInf - - def isInfinity(self): - return self._value in self._inf - - def __str__(self): - return str(float(self)) - - def __add__(self, value): - return self.clone(float(self) + value) - - def __radd__(self, value): - return self + value - - def __mul__(self, value): - return self.clone(float(self) * value) - - def __rmul__(self, value): - return self * value - - def __sub__(self, value): - return self.clone(float(self) - value) - - def __rsub__(self, value): - return self.clone(value - float(self)) - - def __mod__(self, value): - return self.clone(float(self) % value) - - def __rmod__(self, value): - return self.clone(value % float(self)) - - def __pow__(self, value, modulo=None): - return self.clone(pow(float(self), value, modulo)) - - def __rpow__(self, value): - return self.clone(pow(value, float(self))) - - if sys.version_info[0] <= 2: - def __div__(self, value): - return self.clone(float(self) / value) - - def __rdiv__(self, value): - return self.clone(value / float(self)) - else: - def __truediv__(self, value): - return self.clone(float(self) / value) - - def __rtruediv__(self, value): - return self.clone(value / float(self)) - - def __divmod__(self, value): - return self.clone(float(self) // value) - - def __rdivmod__(self, value): - return self.clone(value // float(self)) - - def __int__(self): - return int(float(self)) - - if sys.version_info[0] <= 2: - def __long__(self): return long(float(self)) - - def __float__(self): - if self._value in self._inf: - return self._value - else: - return float( - self._value[0] * pow(self._value[1], self._value[2]) - ) - - def __abs__(self): - return self.clone(abs(float(self))) - - def __pos__(self): - return self.clone(+float(self)) - - def __neg__(self): - return self.clone(-float(self)) - - def __round__(self, n=0): - r = round(float(self), n) - if n: - return self.clone(r) - else: - return r - - def __floor__(self): - return self.clone(math.floor(float(self))) - - def __ceil__(self): - return self.clone(math.ceil(float(self))) - - if sys.version_info[0:2] > (2, 5): - def __trunc__(self): return self.clone(math.trunc(float(self))) - - def __lt__(self, value): - return float(self) < value - - def __le__(self, value): - return float(self) <= value - - def __eq__(self, value): - return float(self) == value - - def __ne__(self, value): - return float(self) != value - - def __gt__(self, value): - return float(self) > value - - def __ge__(self, value): - return float(self) >= value - - if sys.version_info[0] <= 2: - def __nonzero__(self): - return bool(float(self)) - else: - def __bool__(self): - return bool(float(self)) - - __hash__ = base.AbstractSimpleAsn1Item.__hash__ - - def __getitem__(self, idx): - if self._value in self._inf: - raise error.PyAsn1Error('Invalid infinite value operation') - else: - return self._value[idx] - - -class Enumerated(Integer): - __doc__ = Integer.__doc__ - - #: Set (class attribute) or return (class or instance attribute) a - #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) - #: associated with |ASN.1| type. - tagSet = tag.initTagSet( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x0A) - ) - - #: Set (class attribute) or return (class or instance attribute) a - #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object - #: imposing constraints on |ASN.1| type initialization values. - subtypeSpec = constraint.ConstraintsIntersection() - - # Optimization for faster codec lookup - typeId = Integer.getTypeId() - - #: Default :py:class:`~pyasn1.type.namedval.NamedValues` object - #: representing symbolic aliases for numbers - namedValues = namedval.NamedValues() - - -# "Structured" ASN.1 types - -class SequenceOfAndSetOfBase(base.AbstractConstructedAsn1Item): - """Create |ASN.1| type. - - |ASN.1| objects are mutable and duck-type Python :class:`list` objects. - - Parameters - ---------- - componentType : :py:class:`~pyasn1.type.base.PyAsn1Item` derivative - A pyasn1 object representing ASN.1 type allowed within |ASN.1| type - - tagSet: :py:class:`~pyasn1.type.tag.TagSet` - Object representing non-default ASN.1 tag(s) - - subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` - Object representing non-default ASN.1 subtype constraint(s) - - sizeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` - Object representing collection size constraint - """ - - # Python list protocol - - def clear(self): - self._componentValues = [] - - def append(self, value): - self[len(self)] = value - - def count(self, value): - return self._componentValues.count(value) - - def extend(self, values): - for value in values: - self.append(value) - - def index(self, value, start=0, stop=None): - if stop is None: - stop = len(self) - return self._componentValues.index(value, start, stop) - - def reverse(self): - self._componentValues.reverse() - - def sort(self, key=None, reverse=False): - self._componentValues.sort(key=key, reverse=reverse) - - def __iter__(self): - return iter(self._componentValues) - - def _cloneComponentValues(self, myClone, cloneValueFlag): - for idx, componentValue in enumerate(self._componentValues): - if componentValue is not None: - if isinstance(componentValue, base.AbstractConstructedAsn1Item): - myClone.setComponentByPosition( - idx, componentValue.clone(cloneValueFlag=cloneValueFlag) - ) - else: - myClone.setComponentByPosition(idx, componentValue.clone()) - - def getComponentByPosition(self, idx): - """Return |ASN.1| type component value by position. - - Equivalent to Python sequence subscription operation (e.g. `[]`). - - Parameters - ---------- - idx : :class:`int` - Component index (zero-based). Must either refer to an existing - component or to N+1 component (of *componentType is set). In the latter - case a new component type gets instantiated and appended to the |ASN.1| - sequence. - - Returns - ------- - : :py:class:`~pyasn1.type.base.PyAsn1Item` - a pyasn1 object - """ - try: - return self._componentValues[idx] - except IndexError: - self.setComponentByPosition(idx) - return self._componentValues[idx] - - def setComponentByPosition(self, idx, value=noValue, - verifyConstraints=True, - matchTags=True, - matchConstraints=True): - """Assign |ASN.1| type component by position. - - Equivalent to Python sequence item assignment operation (e.g. `[]`) - or list.append() (when idx == len(self)). - - Parameters - ---------- - idx: :class:`int` - Component index (zero-based). Must either refer to existing - component or to N+1 component. In the latter case a new component - type gets instantiated (if *componentType* is set, or given ASN.1 - object is taken otherwise) and appended to the |ASN.1| sequence. - - value: :class:`object` or :py:class:`~pyasn1.type.base.PyAsn1Item` derivative - A Python value to initialize |ASN.1| component with (if *componentType* is set) - or ASN.1 value object to assign to |ASN.1| component. - - verifyConstraints: :class:`bool` - If `False`, skip constraints validation - - matchTags: :class:`bool` - If `False`, skip component tags matching - - matchConstraints: :class:`bool` - If `False`, skip component constraints matching - - Returns - ------- - self - - Raises - ------ - IndexError: - When idx > len(self) - """ - componentType = self._componentType - - try: - currentValue = self._componentValues[idx] - except IndexError: - currentValue = None - - if len(self._componentValues) < idx: - raise error.PyAsn1Error('Component index out of range') - - if value is None or value is noValue: - if componentType is not None: - value = componentType.clone() - elif currentValue is None: - raise error.PyAsn1Error('Component type not defined') - elif not isinstance(value, base.Asn1Item): - if componentType is not None and isinstance(componentType, base.AbstractSimpleAsn1Item): - value = componentType.clone(value=value) - elif currentValue is not None and isinstance(currentValue, base.AbstractSimpleAsn1Item): - value = currentValue.clone(value=value) - else: - raise error.PyAsn1Error('%s undefined component type' % componentType.__class__.__name__) - elif componentType is not None: - if self.strictConstraints: - if not componentType.isSameTypeWith(value, matchTags, matchConstraints): - raise error.PyAsn1Error('Component value is tag-incompatible: %r vs %r' % (value, componentType)) - else: - if not componentType.isSuperTypeOf(value, matchTags, matchConstraints): - raise error.PyAsn1Error('Component value is tag-incompatible: %r vs %r' % (value, componentType)) - - if verifyConstraints and value.isValue: - try: - self._subtypeSpec(value, idx) - - except error.PyAsn1Error: - exType, exValue, exTb = sys.exc_info() - raise exType('%s at %s' % (exValue, self.__class__.__name__)) - - if currentValue is None: - self._componentValues.append(value) - else: - self._componentValues[idx] = value - - return self - - @property - def componentTagMap(self): - if self._componentType is not None: - return self._componentType.tagMap - - def prettyPrint(self, scope=0): - scope += 1 - representation = self.__class__.__name__ + ':\n' - for idx in range(len(self._componentValues)): - representation += ' ' * scope - if self._componentValues[idx] is None: - representation += '' - else: - representation += self._componentValues[idx].prettyPrint(scope) - return representation - - def prettyPrintType(self, scope=0): - scope += 1 - representation = '%s -> %s {\n' % (self.tagSet, self.__class__.__name__) - if self._componentType is not None: - representation += ' ' * scope - representation += self._componentType.prettyPrintType(scope) - return representation + '\n' + ' ' * (scope - 1) + '}' - - - @property - def isValue(self): - """Indicate if |ASN.1| object components represent ASN.1 type or ASN.1 value. - - The PyASN1 type objects can only participate in types comparison - and serve as a blueprint for serialization codecs to resolve - ambiguous types. - - The PyASN1 value objects can additionally participate in most - of built-in Python operations. - - Returns - ------- - : :class:`bool` - :class:`True` if all |ASN.1| components represent value and type, - :class:`False` if at least one |ASN.1| component represents just ASN.1 type. - """ - if not self._componentValues: - return False - - for componentValue in self._componentValues: - if not componentValue.isValue: - return False - - return True - - -class SequenceOf(SequenceOfAndSetOfBase): - __doc__ = SequenceOfAndSetOfBase.__doc__ - - #: Set (class attribute) or return (class or instance attribute) a - #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) - #: associated with |ASN.1| type. - tagSet = tag.initTagSet( - tag.Tag(tag.tagClassUniversal, tag.tagFormatConstructed, 0x10) - ) - - #: Default :py:class:`~pyasn1.type.base.PyAsn1Item` derivative - #: object representing ASN.1 type allowed within |ASN.1| type - componentType = None - - #: Set (class attribute) or return (class or instance attribute) a - #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object - #: imposing constraints on |ASN.1| type initialization values. - subtypeSpec = constraint.ConstraintsIntersection() - - #: Default :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` - #: object imposing size constraint on |ASN.1| objects - sizeSpec = constraint.ConstraintsIntersection() - - # Disambiguation ASN.1 types identification - typeId = SequenceOfAndSetOfBase.getTypeId() - - -class SetOf(SequenceOfAndSetOfBase): - __doc__ = SequenceOfAndSetOfBase.__doc__ - - #: Set (class attribute) or return (class or instance attribute) a - #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) - #: associated with |ASN.1| type. - tagSet = tag.initTagSet( - tag.Tag(tag.tagClassUniversal, tag.tagFormatConstructed, 0x11) - ) - - #: Default :py:class:`~pyasn1.type.base.PyAsn1Item` derivative - #: object representing ASN.1 type allowed within |ASN.1| type - componentType = None - - #: Set (class attribute) or return (class or instance attribute) a - #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object - #: imposing constraints on |ASN.1| type initialization values. - subtypeSpec = constraint.ConstraintsIntersection() - - #: Default :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` - #: object imposing size constraint on |ASN.1| objects - sizeSpec = constraint.ConstraintsIntersection() - - # Disambiguation ASN.1 types identification - typeId = SequenceOfAndSetOfBase.getTypeId() - - -class SequenceAndSetBase(base.AbstractConstructedAsn1Item): - """Create |ASN.1| type. - - |ASN.1| objects are mutable and duck-type Python :class:`dict` objects. - - Parameters - ---------- - componentType: :py:class:`~pyasn1.type.namedtype.NamedType` - Object holding named ASN.1 types allowed within this collection - - tagSet: :py:class:`~pyasn1.type.tag.TagSet` - Object representing non-default ASN.1 tag(s) - - subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` - Object representing non-default ASN.1 subtype constraint(s) - - sizeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` - Object representing collection size constraint - """ - #: Default :py:class:`~pyasn1.type.namedtype.NamedTypes` - #: object representing named ASN.1 types allowed within |ASN.1| type - componentType = namedtype.NamedTypes() - - def __init__(self, componentType=None, tagSet=None, - subtypeSpec=None, sizeSpec=None): - if componentType is None: - componentType = self.componentType - base.AbstractConstructedAsn1Item.__init__( - self, componentType, tagSet, subtypeSpec, sizeSpec - ) - self._componentTypeLen = len(self._componentType) - - def __getitem__(self, idx): - if octets.isStringType(idx): - return self.getComponentByName(idx) - else: - return base.AbstractConstructedAsn1Item.__getitem__(self, idx) - - def __setitem__(self, idx, value): - if octets.isStringType(idx): - self.setComponentByName(idx, value) - else: - base.AbstractConstructedAsn1Item.__setitem__(self, idx, value) - - def __contains__(self, key): - return key in self._componentType - - def __iter__(self): - return iter(self._componentType) - - # Python dict protocol - - def values(self): - for idx in range(self._componentTypeLen): - yield self[idx] - - def keys(self): - return iter(self._componentType) - - def items(self): - for idx in range(self._componentTypeLen): - yield self._componentType[idx].getName(), self[idx] - - def update(self, *iterValue, **mappingValue): - for k, v in iterValue: - self[k] = v - for k in mappingValue: - self[k] = mappingValue[k] - - def clear(self): - self._componentValues = [] - - def _cloneComponentValues(self, myClone, cloneValueFlag): - for idx, componentValue in enumerate(self._componentValues): - if componentValue is not None: - if isinstance(componentValue, base.AbstractConstructedAsn1Item): - myClone.setComponentByPosition( - idx, componentValue.clone(cloneValueFlag=cloneValueFlag) - ) - else: - myClone.setComponentByPosition(idx, componentValue.clone()) - - def getComponentByName(self, name): - """Returns |ASN.1| type component by name. - - Equivalent to Python :class:`dict` subscription operation (e.g. `[]`). - - Parameters - ---------- - name : :class:`str` - |ASN.1| type component name - - Returns - ------- - : :py:class:`~pyasn1.type.base.PyAsn1Item` - Instantiate |ASN.1| component type or return existing component value - """ - return self.getComponentByPosition( - self._componentType.getPositionByName(name) - ) - - def setComponentByName(self, name, value=noValue, - verifyConstraints=True, - matchTags=True, - matchConstraints=True): - """Assign |ASN.1| type component by name. - - Equivalent to Python :class:`dict` item assignment operation (e.g. `[]`). - - Parameters - ---------- - name: :class:`str` - |ASN.1| type component name - - value : :class:`object` or :py:class:`~pyasn1.type.base.PyAsn1Item` derivative - A Python value to initialize |ASN.1| component with (if *componentType* is set) - or ASN.1 value object to assign to |ASN.1| component. - - verifyConstraints: :class:`bool` - If `False`, skip constraints validation - - matchTags: :class:`bool` - If `False`, skip component tags matching - - matchConstraints: :class:`bool` - If `False`, skip component constraints matching - - Returns - ------- - self - """ - return self.setComponentByPosition( - self._componentType.getPositionByName(name), value, verifyConstraints, matchTags, matchConstraints - ) - - def getComponentByPosition(self, idx): - """Returns |ASN.1| type component by index. - - Equivalent to Python sequence subscription operation (e.g. `[]`). - - Parameters - ---------- - idx : :class:`int` - Component index (zero-based). Must either refer to an existing - component or (if *componentType* is set) new ASN.1 type object gets - instantiated. - - Returns - ------- - : :py:class:`~pyasn1.type.base.PyAsn1Item` - a PyASN1 object - """ - try: - componentValue = self._componentValues[idx] - except IndexError: - componentValue = None - - if componentValue is None: - self.setComponentByPosition(idx) - - return self._componentValues[idx] - - def setComponentByPosition(self, idx, value=noValue, - verifyConstraints=True, - matchTags=True, - matchConstraints=True): - """Assign |ASN.1| type component by position. - - Equivalent to Python sequence item assignment operation (e.g. `[]`). - - Parameters - ---------- - idx : :class:`int` - Component index (zero-based). Must either refer to existing - component (if *componentType* is set) or to N+1 component - otherwise. In the latter case a new component of given ASN.1 - type gets instantiated and appended to |ASN.1| sequence. - - value : :class:`object` or :py:class:`~pyasn1.type.base.PyAsn1Item` derivative - A Python value to initialize |ASN.1| component with (if *componentType* is set) - or ASN.1 value object to assign to |ASN.1| component. - - verifyConstraints : :class:`bool` - If `False`, skip constraints validation - - matchTags: :class:`bool` - If `False`, skip component tags matching - - matchConstraints: :class:`bool` - If `False`, skip component constraints matching - - Returns - ------- - self - """ - componentType = self._componentType - componentTypeLen = self._componentTypeLen - - try: - currentValue = self._componentValues[idx] - except IndexError: - currentValue = None - if componentTypeLen: - if componentTypeLen < idx: - raise IndexError('component index out of range') - self._componentValues = [None] * componentTypeLen - - if value is None or value is noValue: - if componentTypeLen: - value = componentType.getTypeByPosition(idx).clone() - elif currentValue is None: - raise error.PyAsn1Error('Component type not defined') - elif not isinstance(value, base.Asn1Item): - if componentTypeLen: - subComponentType = componentType.getTypeByPosition(idx) - if isinstance(subComponentType, base.AbstractSimpleAsn1Item): - value = subComponentType.clone(value=value) - else: - raise error.PyAsn1Error('%s can cast only scalar values' % componentType.__class__.__name__) - elif currentValue is not None and isinstance(currentValue, base.AbstractSimpleAsn1Item): - value = currentValue.clone(value=value) - else: - raise error.PyAsn1Error('%s undefined component type' % componentType.__class__.__name__) - elif (matchTags or matchConstraints) and componentTypeLen: - subComponentType = componentType.getTypeByPosition(idx) - if subComponentType is not None: - if self.strictConstraints: - if not subComponentType.isSameTypeWith(value, matchTags, matchConstraints): - raise error.PyAsn1Error('Component value is tag-incompatible: %r vs %r' % (value, componentType)) - else: - if not subComponentType.isSuperTypeOf(value, matchTags, matchConstraints): - raise error.PyAsn1Error('Component value is tag-incompatible: %r vs %r' % (value, componentType)) - - if verifyConstraints and value.isValue: - try: - self._subtypeSpec(value, idx) - - except error.PyAsn1Error: - exType, exValue, exTb = sys.exc_info() - raise exType('%s at %s' % (exValue, self.__class__.__name__)) - - if componentTypeLen: - self._componentValues[idx] = value - elif len(self._componentValues) == idx: - self._componentValues.append(value) - else: - raise error.PyAsn1Error('Component index out of range') - - return self - - def getNameByPosition(self, idx): - if self._componentTypeLen: - return self._componentType.getNameByPosition(idx) - - def getComponentType(self): - if self._componentTypeLen: - return self._componentType - - @property - def isValue(self): - """Indicate if |ASN.1| object components represent ASN.1 type or ASN.1 value. - - The PyASN1 type objects can only participate in types comparison - and serve as a blueprint for serialization codecs to resolve - ambiguous types. - - The PyASN1 value objects can additionally participate in most - of built-in Python operations. - - Returns - ------- - : :class:`bool` - :class:`True` if all |ASN.1| components represent value and type, - :class:`False` if at least one |ASN.1| component represents just ASN.1 type. - """ - componentType = self._componentType - - if componentType: - for idx, subComponentType in enumerate(componentType.namedTypes): - if subComponentType.isDefaulted or subComponentType.isOptional: - continue - if not self._componentValues or self._componentValues[idx] is None or not self._componentValues[idx].isValue: - return False - - else: - for componentValue in self._componentValues: - if not componentValue.isValue: - return False - - return True - - def prettyPrint(self, scope=0): - """Return an object representation string. - - Returns - ------- - : :class:`str` - Human-friendly object representation. - """ - scope += 1 - representation = self.__class__.__name__ + ':\n' - for idx in range(len(self._componentValues)): - if self._componentValues[idx] is not None: - representation += ' ' * scope - componentType = self.getComponentType() - if componentType is None: - representation += '' - else: - representation += componentType.getNameByPosition(idx) - representation = '%s=%s\n' % ( - representation, self._componentValues[idx].prettyPrint(scope) - ) - return representation - - def prettyPrintType(self, scope=0): - scope += 1 - representation = '%s -> %s {\n' % (self.tagSet, self.__class__.__name__) - for idx in range(len(self.componentType)): - representation += ' ' * scope - representation += '"%s"' % self.componentType.getNameByPosition(idx) - representation = '%s = %s\n' % ( - representation, self._componentType.getTypeByPosition(idx).prettyPrintType(scope) - ) - return representation + '\n' + ' ' * (scope - 1) + '}' - - # backward compatibility -- no-op - def setDefaultComponents(self): - return self - - -class Sequence(SequenceAndSetBase): - __doc__ = SequenceAndSetBase.__doc__ - - #: Set (class attribute) or return (class or instance attribute) a - #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) - #: associated with |ASN.1| type. - tagSet = tag.initTagSet( - tag.Tag(tag.tagClassUniversal, tag.tagFormatConstructed, 0x10) - ) - - #: Set (class attribute) or return (class or instance attribute) a - #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object - #: imposing constraints on |ASN.1| type initialization values. - subtypeSpec = constraint.ConstraintsIntersection() - - #: Default :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` - #: object imposing constraints on |ASN.1| objects - sizeSpec = constraint.ConstraintsIntersection() - - #: Default collection of ASN.1 types of component (e.g. :py:class:`~pyasn1.type.namedtype.NamedType`) - #: object imposing size constraint on |ASN.1| objects - componentType = namedtype.NamedTypes() - - # Disambiguation ASN.1 types identification - typeId = SequenceAndSetBase.getTypeId() - - def getComponentTagMapNearPosition(self, idx): - if self._componentType: - return self._componentType.getTagMapNearPosition(idx) - - def getComponentPositionNearType(self, tagSet, idx): - if self._componentType: - return self._componentType.getPositionNearType(tagSet, idx) - else: - return idx - - -class Set(SequenceAndSetBase): - __doc__ = SequenceAndSetBase.__doc__ - - #: Set (class attribute) or return (class or instance attribute) a - #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) - #: associated with |ASN.1| type. - tagSet = tag.initTagSet( - tag.Tag(tag.tagClassUniversal, tag.tagFormatConstructed, 0x11) - ) - - #: Default collection of ASN.1 types of component (e.g. :py:class:`~pyasn1.type.namedtype.NamedType`) - #: object representing ASN.1 type allowed within |ASN.1| type - componentType = namedtype.NamedTypes() - - #: Set (class attribute) or return (class or instance attribute) a - #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object - #: imposing constraints on |ASN.1| type initialization values. - subtypeSpec = constraint.ConstraintsIntersection() - - #: Default :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` - #: object imposing constraints on |ASN.1| objects - sizeSpec = constraint.ConstraintsIntersection() - - # Disambiguation ASN.1 types identification - typeId = SequenceAndSetBase.getTypeId() - - def getComponent(self, innerFlag=False): - return self - - def getComponentByType(self, tagSet, innerFlag=False): - """Returns |ASN.1| type component by ASN.1 tag. - - Parameters - ---------- - tagSet : :py:class:`~pyasn1.type.tag.TagSet` - Object representing ASN.1 tags to identify one of - |ASN.1| object component - - Returns - ------- - : :py:class:`~pyasn1.type.base.PyAsn1Item` - a pyasn1 object - """ - component = self.getComponentByPosition( - self._componentType.getPositionByType(tagSet) - ) - if innerFlag and isinstance(component, Set): - # get inner component by inner tagSet - return component.getComponent(innerFlag=True) - else: - # get outer component by inner tagSet - return component - - def setComponentByType(self, tagSet, value=noValue, - verifyConstraints=True, - matchTags=True, - matchConstraints=True, - innerFlag=False): - """Assign |ASN.1| type component by ASN.1 tag. - - Parameters - ---------- - tagSet : :py:class:`~pyasn1.type.tag.TagSet` - Object representing ASN.1 tags to identify one of - |ASN.1| object component - - value : :class:`object` or :py:class:`~pyasn1.type.base.PyAsn1Item` derivative - A Python value to initialize |ASN.1| component with (if *componentType* is set) - or ASN.1 value object to assign to |ASN.1| component. - - verifyConstraints : :class:`bool` - If `False`, skip constraints validation - - matchTags: :class:`bool` - If `False`, skip component tags matching - - matchConstraints: :class:`bool` - If `False`, skip component constraints matching - - innerFlag: :class:`bool` - If `True`, search for matching *tagSet* recursively. - - Returns - ------- - self - """ - idx = self._componentType.getPositionByType(tagSet) - - if innerFlag: # set inner component by inner tagSet - componentType = self._componentType.getTypeByPosition(idx) - - if componentType.tagSet: - return self.setComponentByPosition( - idx, value, verifyConstraints, matchTags, matchConstraints - ) - else: - componentType = self.getComponentByPosition(idx) - return componentType.setComponentByType( - tagSet, value, verifyConstraints, matchTags, matchConstraints, innerFlag=innerFlag - ) - else: # set outer component by inner tagSet - return self.setComponentByPosition( - idx, value, verifyConstraints, matchTags, matchConstraints - ) - - @property - def componentTagMap(self): - if self._componentType: - return self._componentType.getTagMap(True) - - def getComponentPositionByType(self, tagSet): - if self._componentType: - return self._componentType.getPositionByType(tagSet) - - -class Choice(Set): - __doc__ = Set.__doc__ - - #: Set (class attribute) or return (class or instance attribute) a - #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) - #: associated with |ASN.1| type. - tagSet = tag.TagSet() # untagged - - #: Default collection of ASN.1 types of component (e.g. :py:class:`~pyasn1.type.namedtype.NamedType`) - #: object representing ASN.1 type allowed within |ASN.1| type - componentType = namedtype.NamedTypes() - - #: Set (class attribute) or return (class or instance attribute) a - #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object - #: imposing constraints on |ASN.1| type initialization values. - subtypeSpec = constraint.ConstraintsIntersection() - - #: Default :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` - #: object imposing size constraint on |ASN.1| objects - sizeSpec = constraint.ConstraintsIntersection( - constraint.ValueSizeConstraint(1, 1) - ) - - # Disambiguation ASN.1 types identification - typeId = Set.getTypeId() - - _currentIdx = None - - def __eq__(self, other): - if self._componentValues: - return self._componentValues[self._currentIdx] == other - return NotImplemented - - def __ne__(self, other): - if self._componentValues: - return self._componentValues[self._currentIdx] != other - return NotImplemented - - def __lt__(self, other): - if self._componentValues: - return self._componentValues[self._currentIdx] < other - return NotImplemented - - def __le__(self, other): - if self._componentValues: - return self._componentValues[self._currentIdx] <= other - return NotImplemented - - def __gt__(self, other): - if self._componentValues: - return self._componentValues[self._currentIdx] > other - return NotImplemented - - def __ge__(self, other): - if self._componentValues: - return self._componentValues[self._currentIdx] >= other - return NotImplemented - - if sys.version_info[0] <= 2: - def __nonzero__(self): - return self._componentValues and True or False - else: - def __bool__(self): - return self._componentValues and True or False - - def __len__(self): - return self._currentIdx is not None and 1 or 0 - - def __contains__(self, key): - if self._currentIdx is None: - return False - return key == self._componentType[self._currentIdx].getName() - - def __iter__(self): - if self._currentIdx is None: - raise StopIteration - yield self._componentType[self._currentIdx].getName() - - # Python dict protocol - - def values(self): - if self._currentIdx is not None: - yield self._componentValues[self._currentIdx] - - def keys(self): - if self._currentIdx is not None: - yield self._componentType[self._currentIdx].getName() - - def items(self): - if self._currentIdx is not None: - yield self._componentType[self._currentIdx].getName(), self[self._currentIdx] - - def verifySizeSpec(self): - if self._currentIdx is None: - raise error.PyAsn1Error('Component not chosen') - - def _cloneComponentValues(self, myClone, cloneValueFlag): - try: - component = self.getComponent() - except error.PyAsn1Error: - pass - else: - if isinstance(component, Choice): - tagSet = component.effectiveTagSet - else: - tagSet = component.tagSet - if isinstance(component, base.AbstractConstructedAsn1Item): - myClone.setComponentByType( - tagSet, component.clone(cloneValueFlag=cloneValueFlag) - ) - else: - myClone.setComponentByType(tagSet, component.clone()) - - def getComponentByPosition(self, idx): - __doc__ = Set.__doc__ - - if self._currentIdx is None or self._currentIdx != idx: - return Set.getComponentByPosition(self, idx) - - return self._componentValues[idx] - - def setComponentByPosition(self, idx, value=noValue, - verifyConstraints=True, - matchTags=True, - matchConstraints=True): - """Assign |ASN.1| type component by position. - - Equivalent to Python sequence item assignment operation (e.g. `[]`). - - Parameters - ---------- - idx: :class:`int` - Component index (zero-based). Must either refer to existing - component or to N+1 component. In the latter case a new component - type gets instantiated (if *componentType* is set, or given ASN.1 - object is taken otherwise) and appended to the |ASN.1| sequence. - - value: :class:`object` or :py:class:`~pyasn1.type.base.PyAsn1Item` derivative - A Python value to initialize |ASN.1| component with (if *componentType* is set) - or ASN.1 value object to assign to |ASN.1| component. Once a new value is - set to *idx* component, previous value is dropped. - - verifyConstraints : :class:`bool` - If `False`, skip constraints validation - - matchTags: :class:`bool` - If `False`, skip component tags matching - - matchConstraints: :class:`bool` - If `False`, skip component constraints matching - - Returns - ------- - self - """ - oldIdx = self._currentIdx - Set.setComponentByPosition(self, idx, value, verifyConstraints, matchTags, matchConstraints) - self._currentIdx = idx - if oldIdx is not None and oldIdx != idx: - self._componentValues[oldIdx] = None - return self - - def getMinTagSet(self): - if self._tagSet: - return self._tagSet - else: - return self._componentType.minTagSet - - @property - def effectiveTagSet(self): - """Return a :class:`~pyasn1.type.tag.TagSet` object of the currently initialized component or self (if |ASN.1| is tagged).""" - if self._tagSet: - return self._tagSet - else: - component = self.getComponent() - return component.effectiveTagSet - - @property - def tagMap(self): - """"Return a :class:`~pyasn1.type.tagmap.TagMap` object mapping - ASN.1 tags to ASN.1 objects contained within callee. - """ - if self._tagSet: - return Set.tagMap.fget(self) - else: - return Set.componentTagMap.fget(self) - - def getComponent(self, innerFlag=0): - """Return currently assigned component of the |ASN.1| object. - - Returns - ------- - : :py:class:`~pyasn1.type.base.PyAsn1Item` - a PyASN1 object - """ - if self._currentIdx is None: - raise error.PyAsn1Error('Component not chosen') - else: - c = self._componentValues[self._currentIdx] - if innerFlag and isinstance(c, Choice): - return c.getComponent(innerFlag) - else: - return c - - def getName(self, innerFlag=False): - """Return the name of currently assigned component of the |ASN.1| object. - - Returns - ------- - : :py:class:`str` - |ASN.1| component name - """ - if self._currentIdx is None: - raise error.PyAsn1Error('Component not chosen') - else: - if innerFlag: - c = self._componentValues[self._currentIdx] - if isinstance(c, Choice): - return c.getName(innerFlag) - return self._componentType.getNameByPosition(self._currentIdx) - - @property - def isValue(self): - """Indicate if |ASN.1| component is set and represents ASN.1 type or ASN.1 value. - - The PyASN1 type objects can only participate in types comparison - and serve as a blueprint for serialization codecs to resolve - ambiguous types. - - The PyASN1 value objects can additionally participate in most - of built-in Python operations. - - Returns - ------- - : :class:`bool` - :class:`True` if |ASN.1| component is set and represent value and type, - :class:`False` if |ASN.1| component is not set or it represents just ASN.1 type. - """ - if self._currentIdx is None: - return False - - return self._componentValues[self._currentIdx].isValue - - -class Any(OctetString): - __doc__ = OctetString.__doc__ - - #: Set (class attribute) or return (class or instance attribute) a - #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) - #: associated with |ASN.1| type. - tagSet = tag.TagSet() # untagged - - #: Set (class attribute) or return (class or instance attribute) a - #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object - #: imposing constraints on |ASN.1| type initialization values. - subtypeSpec = constraint.ConstraintsIntersection() - - # Disambiguation ASN.1 types identification - typeId = OctetString.getTypeId() - - @property - def tagMap(self): - """"Return a :class:`~pyasn1.type.tagmap.TagMap` object mapping - ASN.1 tags to ASN.1 objects contained within callee. - """ - try: - return self._tagMap - - except AttributeError: - self._tagMap = tagmap.TagMap( - {self.tagSet: self}, - {eoo.endOfOctets.tagSet: eoo.endOfOctets}, - self - ) - - return self._tagMap - -# XXX -# coercion rules? diff --git a/src/lib/pyasn1/type/useful.py b/src/lib/pyasn1/type/useful.py deleted file mode 100644 index 0b79a983..00000000 --- a/src/lib/pyasn1/type/useful.py +++ /dev/null @@ -1,39 +0,0 @@ -# -# This file is part of pyasn1 software. -# -# Copyright (c) 2005-2017, Ilya Etingof -# License: http://pyasn1.sf.net/license.html -# -from pyasn1.type import univ, char, tag - -__all__ = ['ObjectDescriptor', 'GeneralizedTime', 'UTCTime'] - -NoValue = univ.NoValue -noValue = univ.noValue - - -class ObjectDescriptor(char.GraphicString): - __doc__ = char.GraphicString.__doc__ - - #: Default :py:class:`~pyasn1.type.tag.TagSet` object for |ASN.1| objects - tagSet = char.GraphicString.tagSet.tagImplicitly( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 7) - ) - - -class GeneralizedTime(char.VisibleString): - __doc__ = char.GraphicString.__doc__ - - #: Default :py:class:`~pyasn1.type.tag.TagSet` object for |ASN.1| objects - tagSet = char.VisibleString.tagSet.tagImplicitly( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 24) - ) - - -class UTCTime(char.VisibleString): - __doc__ = char.GraphicString.__doc__ - - #: Default :py:class:`~pyasn1.type.tag.TagSet` object for |ASN.1| objects - tagSet = char.VisibleString.tagSet.tagImplicitly( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 23) - ) diff --git a/src/lib/pybitcointools/LICENSE b/src/lib/pybitcointools/LICENSE deleted file mode 100644 index c47d4ad0..00000000 --- a/src/lib/pybitcointools/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -This code is public domain. Everyone has the right to do whatever they want -with it for any purpose. - -In case your jurisdiction does not consider the above disclaimer valid or -enforceable, here's an MIT license for you: - -The MIT License (MIT) - -Copyright (c) 2013 Vitalik Buterin - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/src/lib/pybitcointools/MANIFEST.in b/src/lib/pybitcointools/MANIFEST.in deleted file mode 100644 index 70656b68..00000000 --- a/src/lib/pybitcointools/MANIFEST.in +++ /dev/null @@ -1 +0,0 @@ -include bitcoin/english.txt diff --git a/src/lib/pybitcointools/README.md b/src/lib/pybitcointools/README.md deleted file mode 100644 index 2f2876e7..00000000 --- a/src/lib/pybitcointools/README.md +++ /dev/null @@ -1,142 +0,0 @@ -# Pybitcointools, Python library for Bitcoin signatures and transactions - -### Advantages: - -* Functions have a simple interface, inputting and outputting in standard formats -* No classes -* Many functions can be taken out and used individually -* Supports binary, hex and base58 -* Transaction deserialization format almost compatible with BitcoinJS -* Electrum and BIP0032 support -* Make and publish a transaction all in a single command line instruction -* Includes non-bitcoin-specific conversion and JSON utilities - -### Disadvantages: - -* Not a full node, has no idea what blocks are -* Relies on centralized service (blockchain.info) for blockchain operations, although operations do have backups (eligius, blockr.io) - -### Example usage (best way to learn :) ): - - > from bitcoin import * - > priv = sha256('some big long brainwallet password') - > priv - '57c617d9b4e1f7af6ec97ca2ff57e94a28279a7eedd4d12a99fa11170e94f5a4' - > pub = privtopub(priv) - > pub - '0420f34c2786b4bae593e22596631b025f3ff46e200fc1d4b52ef49bbdc2ed00b26c584b7e32523fb01be2294a1f8a5eb0cf71a203cc034ced46ea92a8df16c6e9' - > addr = pubtoaddr(pub) - > addr - '1CQLd3bhw4EzaURHbKCwM5YZbUQfA4ReY6' - > h = history(addr) - > h - [{'output': u'97f7c7d8ac85e40c255f8a763b6cd9a68f3a94d2e93e8bfa08f977b92e55465e:0', 'value': 50000, 'address': u'1CQLd3bhw4EzaURHbKCwM5YZbUQfA4ReY6'}, {'output': u'4cc806bb04f730c445c60b3e0f4f44b54769a1c196ca37d8d4002135e4abd171:1', 'value': 50000, 'address': u'1CQLd3bhw4EzaURHbKCwM5YZbUQfA4ReY6'}] - > outs = [{'value': 90000, 'address': '16iw1MQ1sy1DtRPYw3ao1bCamoyBJtRB4t'}] - > tx = mktx(h,outs) - > tx - '01000000025e46552eb977f908fa8b3ee9d2943a8fa6d96c3b768a5f250ce485acd8c7f7970000000000ffffffff71d1abe4352100d4d837ca96c1a16947b5444f0f3e0bc645c430f704bb06c84c0100000000ffffffff01905f0100000000001976a9143ec6c3ed8dfc3ceabcc1cbdb0c5aef4e2d02873c88ac00000000' - > tx2 = sign(tx,0,priv) - > tx2 - '01000000025e46552eb977f908fa8b3ee9d2943a8fa6d96c3b768a5f250ce485acd8c7f797000000008b483045022100dd29d89a28451febb990fb1dafa21245b105140083ced315ebcdea187572b3990220713f2e554f384d29d7abfedf39f0eb92afba0ef46f374e49d43a728a0ff6046e01410420f34c2786b4bae593e22596631b025f3ff46e200fc1d4b52ef49bbdc2ed00b26c584b7e32523fb01be2294a1f8a5eb0cf71a203cc034ced46ea92a8df16c6e9ffffffff71d1abe4352100d4d837ca96c1a16947b5444f0f3e0bc645c430f704bb06c84c0100000000ffffffff01905f0100000000001976a9143ec6c3ed8dfc3ceabcc1cbdb0c5aef4e2d02873c88ac00000000' - > tx3 = sign(tx2,1,priv) - > tx3 - '01000000025e46552eb977f908fa8b3ee9d2943a8fa6d96c3b768a5f250ce485acd8c7f797000000008b483045022100dd29d89a28451febb990fb1dafa21245b105140083ced315ebcdea187572b3990220713f2e554f384d29d7abfedf39f0eb92afba0ef46f374e49d43a728a0ff6046e01410420f34c2786b4bae593e22596631b025f3ff46e200fc1d4b52ef49bbdc2ed00b26c584b7e32523fb01be2294a1f8a5eb0cf71a203cc034ced46ea92a8df16c6e9ffffffff71d1abe4352100d4d837ca96c1a16947b5444f0f3e0bc645c430f704bb06c84c010000008c4930460221008bbaaaf172adfefc3a1315dc7312c88645832ff76d52e0029d127e65bbeeabe1022100fdeb89658d503cf2737cedb4049e5070f689c50a9b6c85997d49e0787938f93901410420f34c2786b4bae593e22596631b025f3ff46e200fc1d4b52ef49bbdc2ed00b26c584b7e32523fb01be2294a1f8a5eb0cf71a203cc034ced46ea92a8df16c6e9ffffffff01905f0100000000001976a9143ec6c3ed8dfc3ceabcc1cbdb0c5aef4e2d02873c88ac00000000' - > pushtx(tx3) - 'Transaction Submitted' - -Or using the pybtctool command line interface: - - @vub: pybtctool random_electrum_seed - 484ccb566edb66c65dd0fd2e4d90ef65 - - @vub: pybtctool electrum_privkey 484ccb566edb66c65dd0fd2e4d90ef65 0 0 - 593240c2205e7b7b5d7c13393b7c9553497854b75c7470b76aeca50cd4a894d7 - - @vub: pybtctool electrum_mpk 484ccb566edb66c65dd0fd2e4d90ef65 - 484e42865b8e9a6ea8262fd1cde666b557393258ed598d842e563ad9e5e6c70a97e387eefdef123c1b8b4eb21fe210c6216ad7cc1e4186fbbba70f0e2c062c25 - - @vub: pybtctool bip32_master_key 21456t243rhgtucyadh3wgyrcubw3grydfbng - xprv9s21ZrQH143K2napkeoHT48gWmoJa89KCQj4nqLfdGybyWHP9Z8jvCGzuEDv4ihCyoed7RFPNbc9NxoSF7cAvH9AaNSvepUaeqbSpJZ4rbT - - @vub: pybtctool bip32_ckd xprv9s21ZrQH143K2napkeoHT48gWmoJa89KCQj4nqLfdGybyWHP9Z8jvCGzuEDv4ihCyoed7RFPNbc9NxoSF7cAvH9AaNSvepUaeqbSpJZ4rbT 0 - xprv9vfzYrpwo7QHFdtrcvsSCTrBESFPUf1g7NRvayy1QkEfUekpDKLfqvHjgypF5w3nAvnwPjtQUNkyywWNkLbiUS95khfHCzJXFkLEdwRepbw - - @vub: pybtctool bip32_privtopub xprv9s21ZrQH143K2napkeoHT48gWmoJa89KCQj4nqLfdGybyWHP9Z8jvCGzuEDv4ihCyoed7RFPNbc9NxoSF7cAvH9AaNSvepUaeqbSpJZ4rbT - xpub661MyMwAqRbcFGfHrgLHpC5R4odnyasAZdefbDkHBcWarJcXh6SzTzbUkWuhnP142ZFdKdAJSuTSaiGDYjvm7bCLmA8DZqksYjJbYmcgrYF - -The -s option lets you read arguments from the command line - - @vub: pybtctool sha256 'some big long brainwallet password' | pybtctool -s privtoaddr | pybtctool -s history - [{'output': u'97f7c7d8ac85e40c255f8a763b6cd9a68f3a94d2e93e8bfa08f977b92e55465e:0', 'value': 50000, 'address': u'1CQLd3bhw4EzaURHbKCwM5YZbUQfA4ReY6'}, {'output': u'4cc806bb04f730c445c60b3e0f4f44b54769a1c196ca37d8d4002135e4abd171:1', 'value': 50000, 'address': u'1CQLd3bhw4EzaURHbKCwM5YZbUQfA4ReY6'}] - @vub: pybtctool random_electrum_seed | pybtctool -s electrum_privkey 0 0 - 593240c2205e7b7b5d7c13393b7c9553497854b75c7470b76aeca50cd4a894d7 - -The -b option lets you read binary data as an argument - - @vub: pybtctool sha256 123 | pybtctool -s changebase 16 256 | pybtctool -b changebase 256 16 - a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae30a - -The -j option lets you read json from the command line (-J to split a json list into multiple arguments) - - @vub: pybtctool unspent 1FxkfJQLJTXpW6QmxGT6oF43ZH959ns8Cq | pybtctool -j select 200000001 | pybtctool -j mksend 1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P:20000 1FxkfJQLJTXpW6QmxGT6oF43ZH959ns8Cq 1000 | pybtctool -s signall 805cd74ca322633372b9bfb857f3be41db0b8de43a3c44353b238c0acff9d523 - 0100000003d5001aae8358ae98cb02c1b6f9859dc1ac3dbc1e9cc88632afeb7b7e3c510a49000000008b4830450221009e03bb6122437767e2ca785535824f4ed13d2ebbb9fa4f9becc6d6f4e1e217dc022064577353c08d8d974250143d920d3b963b463e43bbb90f3371060645c49266b90141048ef80f6bd6b073407a69299c2ba89de48adb59bb9689a5ab040befbbebcfbb15d01b006a6b825121a0d2c546c277acb60f0bd3203bd501b8d67c7dba91f27f47ffffffff1529d655dff6a0f6c9815ee835312fb3ca4df622fde21b6b9097666e9284087d010000008a473044022035dd67d18b575ebd339d05ca6ffa1d27d7549bd993aeaf430985795459fc139402201aaa162cc50181cee493870c9479b1148243a33923cb77be44a73ca554a4e5d60141048ef80f6bd6b073407a69299c2ba89de48adb59bb9689a5ab040befbbebcfbb15d01b006a6b825121a0d2c546c277acb60f0bd3203bd501b8d67c7dba91f27f47ffffffff23d5f9cf0a8c233b35443c3ae48d0bdb41bef357b8bfb972336322a34cd75c80010000008b483045022014daa5c5bbe9b3e5f2539a5cd8e22ce55bc84788f946c5b3643ecac85b4591a9022100a4062074a1df3fa0aea5ef67368d0b1f0eaac520bee6e417c682d83cd04330450141048ef80f6bd6b073407a69299c2ba89de48adb59bb9689a5ab040befbbebcfbb15d01b006a6b825121a0d2c546c277acb60f0bd3203bd501b8d67c7dba91f27f47ffffffff02204e0000000000001976a914946cb2e08075bcbaf157e47bcb67eb2b2339d24288ac5b3c4411000000001976a914a41d15ae657ad3bfd0846771a34d7584c37d54a288ac00000000 - -Fun stuff with json: - - @vub: pybtctool history 1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P | pybtctool -j multiaccess value | pybtctool -j sum - 625216206372 - - @vub: pybtctool history 1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P | pybtctool -j count - 6198 - -### Listing of main commands: - -* privkey_to_pubkey : (privkey) -> pubkey -* privtopub : (privkey) -> pubkey -* pubkey_to_address : (pubkey) -> address -* pubtoaddr : (pubkey) -> address -* privkey_to_address : (privkey) -> address -* privtoaddr : (privkey) -> address - -* add : (key1, key2) -> key1 + key2 (works on privkeys or pubkeys) -* multiply : (pubkey, privkey) -> returns pubkey * privkey - -* ecdsa_sign : (message, privkey) -> sig -* ecdsa_verify : (message, sig, pubkey) -> True/False -* ecdsa_recover : (message, sig) -> pubkey - -* random_key : () -> privkey -* random_electrum_seed : () -> electrum seed - -* electrum_stretch : (seed) -> secret exponent -* electrum_privkey : (seed or secret exponent, i, type) -> privkey -* electrum_mpk : (seed or secret exponent) -> master public key -* electrum_pubkey : (seed or secexp or mpk) -> pubkey - -* bip32_master_key : (seed) -> bip32 master key -* bip32_ckd : (private or public bip32 key, i) -> child key -* bip32_privtopub : (private bip32 key) -> public bip32 key -* bip32_extract_key : (private or public bip32_key) -> privkey or pubkey - -* deserialize : (hex or bin transaction) -> JSON tx -* serialize : (JSON tx) -> hex or bin tx -* mktx : (inputs, outputs) -> tx -* mksend : (inputs, outputs, change_addr, fee) -> tx -* sign : (tx, i, privkey) -> tx with index i signed with privkey -* multisign : (tx, i, script, privkey) -> signature -* apply_multisignatures: (tx, i, script, sigs) -> tx with index i signed with sigs -* scriptaddr : (script) -> P2SH address -* mk_multisig_script : (pubkeys, k, n) -> k-of-n multisig script from pubkeys -* verify_tx_input : (tx, i, script, sig, pub) -> True/False -* tx_hash : (hex or bin tx) -> hash - -* history : (address1, address2, etc) -> outputs to those addresses -* unspent : (address1, address2, etc) -> unspent outputs to those addresses -* fetchtx : (txash) -> tx if present -* pushtx : (hex or bin tx) -> tries to push to blockchain.info/pushtx - -* access : (json list/object, prop) -> desired property of that json object -* multiaccess : (json list, prop) -> like access, but mapped across each list element -* slice : (json list, start, end) -> given slice of the list -* count : (json list) -> number of elements -* sum : (json list) -> sum of all values diff --git a/src/lib/pybitcointools/__init__.py b/src/lib/pybitcointools/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/lib/pybitcointools/bitcoin/__init__.py b/src/lib/pybitcointools/bitcoin/__init__.py deleted file mode 100644 index 7d529abc..00000000 --- a/src/lib/pybitcointools/bitcoin/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -from .py2specials import * -from .py3specials import * -from .main import * -from .transaction import * -from .deterministic import * -from .bci import * -from .composite import * -from .stealth import * -from .blocks import * -from .mnemonic import * diff --git a/src/lib/pybitcointools/bitcoin/bci.py b/src/lib/pybitcointools/bitcoin/bci.py deleted file mode 100644 index 79a2c401..00000000 --- a/src/lib/pybitcointools/bitcoin/bci.py +++ /dev/null @@ -1,528 +0,0 @@ -#!/usr/bin/python -import json, re -import random -import sys -try: - from urllib.request import build_opener -except: - from urllib2 import build_opener - - -# Makes a request to a given URL (first arg) and optional params (second arg) -def make_request(*args): - opener = build_opener() - opener.addheaders = [('User-agent', - 'Mozilla/5.0'+str(random.randrange(1000000)))] - try: - return opener.open(*args).read().strip() - except Exception as e: - try: - p = e.read().strip() - except: - p = e - raise Exception(p) - - -def is_testnet(inp): - '''Checks if inp is a testnet address or if UTXO is a known testnet TxID''' - if isinstance(inp, (list, tuple)) and len(inp) >= 1: - return any([is_testnet(x) for x in inp]) - elif not isinstance(inp, basestring): # sanity check - raise TypeError("Input must be str/unicode, not type %s" % str(type(inp))) - - if not inp or (inp.lower() in ("btc", "testnet")): - pass - - ## ADDRESSES - if inp[0] in "123mn": - if re.match("^[2mn][a-km-zA-HJ-NP-Z0-9]{26,33}$", inp): - return True - elif re.match("^[13][a-km-zA-HJ-NP-Z0-9]{26,33}$", inp): - return False - else: - #sys.stderr.write("Bad address format %s") - return None - - ## TXID - elif re.match('^[0-9a-fA-F]{64}$', inp): - base_url = "http://api.blockcypher.com/v1/btc/{network}/txs/{txid}?includesHex=false" - try: - # try testnet fetchtx - make_request(base_url.format(network="test3", txid=inp.lower())) - return True - except: - # try mainnet fetchtx - make_request(base_url.format(network="main", txid=inp.lower())) - return False - sys.stderr.write("TxID %s has no match for testnet or mainnet (Bad TxID)") - return None - else: - raise TypeError("{0} is unknown input".format(inp)) - - -def set_network(*args): - '''Decides if args for unspent/fetchtx/pushtx are mainnet or testnet''' - r = [] - for arg in args: - if not arg: - pass - if isinstance(arg, basestring): - r.append(is_testnet(arg)) - elif isinstance(arg, (list, tuple)): - return set_network(*arg) - if any(r) and not all(r): - raise Exception("Mixed Testnet/Mainnet queries") - return "testnet" if any(r) else "btc" - - -def parse_addr_args(*args): - # Valid input formats: unspent([addr1, addr2, addr3]) - # unspent([addr1, addr2, addr3], network) - # unspent(addr1, addr2, addr3) - # unspent(addr1, addr2, addr3, network) - addr_args = args - network = "btc" - if len(args) == 0: - return [], 'btc' - if len(args) >= 1 and args[-1] in ('testnet', 'btc'): - network = args[-1] - addr_args = args[:-1] - if len(addr_args) == 1 and isinstance(addr_args, list): - network = set_network(*addr_args[0]) - addr_args = addr_args[0] - if addr_args and isinstance(addr_args, tuple) and isinstance(addr_args[0], list): - addr_args = addr_args[0] - network = set_network(addr_args) - return network, addr_args - - -# Gets the unspent outputs of one or more addresses -def bci_unspent(*args): - network, addrs = parse_addr_args(*args) - u = [] - for a in addrs: - try: - data = make_request('https://blockchain.info/unspent?active='+a) - except Exception as e: - if str(e) == 'No free outputs to spend': - continue - else: - raise Exception(e) - try: - jsonobj = json.loads(data.decode("utf-8")) - for o in jsonobj["unspent_outputs"]: - h = o['tx_hash'].decode('hex')[::-1].encode('hex') - u.append({ - "output": h+':'+str(o['tx_output_n']), - "value": o['value'] - }) - except: - raise Exception("Failed to decode data: "+data) - return u - - -def blockr_unspent(*args): - # Valid input formats: blockr_unspent([addr1, addr2,addr3]) - # blockr_unspent(addr1, addr2, addr3) - # blockr_unspent([addr1, addr2, addr3], network) - # blockr_unspent(addr1, addr2, addr3, network) - # Where network is 'btc' or 'testnet' - network, addr_args = parse_addr_args(*args) - - if network == 'testnet': - blockr_url = 'http://tbtc.blockr.io/api/v1/address/unspent/' - elif network == 'btc': - blockr_url = 'http://btc.blockr.io/api/v1/address/unspent/' - else: - raise Exception( - 'Unsupported network {0} for blockr_unspent'.format(network)) - - if len(addr_args) == 0: - return [] - elif isinstance(addr_args[0], list): - addrs = addr_args[0] - else: - addrs = addr_args - res = make_request(blockr_url+','.join(addrs)) - data = json.loads(res.decode("utf-8"))['data'] - o = [] - if 'unspent' in data: - data = [data] - for dat in data: - for u in dat['unspent']: - o.append({ - "output": u['tx']+':'+str(u['n']), - "value": int(u['amount'].replace('.', '')) - }) - return o - - -def helloblock_unspent(*args): - addrs, network = parse_addr_args(*args) - if network == 'testnet': - url = 'https://testnet.helloblock.io/v1/addresses/%s/unspents?limit=500&offset=%s' - elif network == 'btc': - url = 'https://mainnet.helloblock.io/v1/addresses/%s/unspents?limit=500&offset=%s' - o = [] - for addr in addrs: - for offset in xrange(0, 10**9, 500): - res = make_request(url % (addr, offset)) - data = json.loads(res.decode("utf-8"))["data"] - if not len(data["unspents"]): - break - elif offset: - sys.stderr.write("Getting more unspents: %d\n" % offset) - for dat in data["unspents"]: - o.append({ - "output": dat["txHash"]+':'+str(dat["index"]), - "value": dat["value"], - }) - return o - - -unspent_getters = { - 'bci': bci_unspent, - 'blockr': blockr_unspent, - 'helloblock': helloblock_unspent -} - - -def unspent(*args, **kwargs): - f = unspent_getters.get(kwargs.get('source', ''), bci_unspent) - return f(*args) - - -# Gets the transaction output history of a given set of addresses, -# including whether or not they have been spent -def history(*args): - # Valid input formats: history([addr1, addr2,addr3]) - # history(addr1, addr2, addr3) - if len(args) == 0: - return [] - elif isinstance(args[0], list): - addrs = args[0] - else: - addrs = args - - txs = [] - for addr in addrs: - offset = 0 - while 1: - gathered = False - while not gathered: - try: - data = make_request( - 'https://blockchain.info/address/%s?format=json&offset=%s' % - (addr, offset)) - gathered = True - except Exception as e: - try: - sys.stderr.write(e.read().strip()) - except: - sys.stderr.write(str(e)) - gathered = False - try: - jsonobj = json.loads(data.decode("utf-8")) - except: - raise Exception("Failed to decode data: "+data) - txs.extend(jsonobj["txs"]) - if len(jsonobj["txs"]) < 50: - break - offset += 50 - sys.stderr.write("Fetching more transactions... "+str(offset)+'\n') - outs = {} - for tx in txs: - for o in tx["out"]: - if o.get('addr', None) in addrs: - key = str(tx["tx_index"])+':'+str(o["n"]) - outs[key] = { - "address": o["addr"], - "value": o["value"], - "output": tx["hash"]+':'+str(o["n"]), - "block_height": tx.get("block_height", None) - } - for tx in txs: - for i, inp in enumerate(tx["inputs"]): - if "prev_out" in inp: - if inp["prev_out"].get("addr", None) in addrs: - key = str(inp["prev_out"]["tx_index"]) + \ - ':'+str(inp["prev_out"]["n"]) - if outs.get(key): - outs[key]["spend"] = tx["hash"]+':'+str(i) - return [outs[k] for k in outs] - - -# Pushes a transaction to the network using https://blockchain.info/pushtx -def bci_pushtx(tx): - if not re.match('^[0-9a-fA-F]*$', tx): - tx = tx.encode('hex') - return make_request('https://blockchain.info/pushtx', 'tx='+tx) - - -def eligius_pushtx(tx): - if not re.match('^[0-9a-fA-F]*$', tx): - tx = tx.encode('hex') - s = make_request( - 'http://eligius.st/~wizkid057/newstats/pushtxn.php', - 'transaction='+tx+'&send=Push') - strings = re.findall('string[^"]*"[^"]*"', s) - for string in strings: - quote = re.findall('"[^"]*"', string)[0] - if len(quote) >= 5: - return quote[1:-1] - - -def blockr_pushtx(tx, network='btc'): - if network == 'testnet': - blockr_url = 'http://tbtc.blockr.io/api/v1/tx/push' - elif network == 'btc': - blockr_url = 'http://btc.blockr.io/api/v1/tx/push' - else: - raise Exception( - 'Unsupported network {0} for blockr_pushtx'.format(network)) - - if not re.match('^[0-9a-fA-F]*$', tx): - tx = tx.encode('hex') - return make_request(blockr_url, '{"hex":"%s"}' % tx) - - -def helloblock_pushtx(tx): - if not re.match('^[0-9a-fA-F]*$', tx): - tx = tx.encode('hex') - return make_request('https://mainnet.helloblock.io/v1/transactions', - 'rawTxHex='+tx) - -pushtx_getters = { - 'bci': bci_pushtx, - 'blockr': blockr_pushtx, - 'helloblock': helloblock_pushtx -} - - -def pushtx(*args, **kwargs): - f = pushtx_getters.get(kwargs.get('source', ''), bci_pushtx) - return f(*args) - - -def last_block_height(network='btc'): - if network == 'testnet': - data = make_request('http://tbtc.blockr.io/api/v1/block/info/last') - jsonobj = json.loads(data.decode("utf-8")) - return jsonobj["data"]["nb"] - - data = make_request('https://blockchain.info/latestblock') - jsonobj = json.loads(data.decode("utf-8")) - return jsonobj["height"] - - -# Gets a specific transaction -def bci_fetchtx(txhash): - if isinstance(txhash, list): - return [bci_fetchtx(h) for h in txhash] - if not re.match('^[0-9a-fA-F]*$', txhash): - txhash = txhash.encode('hex') - data = make_request('https://blockchain.info/rawtx/'+txhash+'?format=hex') - return data - - -def blockr_fetchtx(txhash, network='btc'): - if network == 'testnet': - blockr_url = 'http://tbtc.blockr.io/api/v1/tx/raw/' - elif network == 'btc': - blockr_url = 'http://btc.blockr.io/api/v1/tx/raw/' - else: - raise Exception( - 'Unsupported network {0} for blockr_fetchtx'.format(network)) - if isinstance(txhash, list): - txhash = ','.join([x.encode('hex') if not re.match('^[0-9a-fA-F]*$', x) - else x for x in txhash]) - jsondata = json.loads(make_request(blockr_url+txhash).decode("utf-8")) - return [d['tx']['hex'] for d in jsondata['data']] - else: - if not re.match('^[0-9a-fA-F]*$', txhash): - txhash = txhash.encode('hex') - jsondata = json.loads(make_request(blockr_url+txhash).decode("utf-8")) - return jsondata['data']['tx']['hex'] - - -def helloblock_fetchtx(txhash, network='btc'): - if isinstance(txhash, list): - return [helloblock_fetchtx(h) for h in txhash] - if not re.match('^[0-9a-fA-F]*$', txhash): - txhash = txhash.encode('hex') - if network == 'testnet': - url = 'https://testnet.helloblock.io/v1/transactions/' - elif network == 'btc': - url = 'https://mainnet.helloblock.io/v1/transactions/' - else: - raise Exception( - 'Unsupported network {0} for helloblock_fetchtx'.format(network)) - data = json.loads(make_request(url + txhash).decode("utf-8"))["data"]["transaction"] - o = { - "locktime": data["locktime"], - "version": data["version"], - "ins": [], - "outs": [] - } - for inp in data["inputs"]: - o["ins"].append({ - "script": inp["scriptSig"], - "outpoint": { - "index": inp["prevTxoutIndex"], - "hash": inp["prevTxHash"], - }, - "sequence": 4294967295 - }) - for outp in data["outputs"]: - o["outs"].append({ - "value": outp["value"], - "script": outp["scriptPubKey"] - }) - from .transaction import serialize - from .transaction import txhash as TXHASH - tx = serialize(o) - assert TXHASH(tx) == txhash - return tx - - -fetchtx_getters = { - 'bci': bci_fetchtx, - 'blockr': blockr_fetchtx, - 'helloblock': helloblock_fetchtx -} - - -def fetchtx(*args, **kwargs): - f = fetchtx_getters.get(kwargs.get('source', ''), bci_fetchtx) - return f(*args) - - -def firstbits(address): - if len(address) >= 25: - return make_request('https://blockchain.info/q/getfirstbits/'+address) - else: - return make_request( - 'https://blockchain.info/q/resolvefirstbits/'+address) - - -def get_block_at_height(height): - j = json.loads(make_request("https://blockchain.info/block-height/" + - str(height)+"?format=json").decode("utf-8")) - for b in j['blocks']: - if b['main_chain'] is True: - return b - raise Exception("Block at this height not found") - - -def _get_block(inp): - if len(str(inp)) < 64: - return get_block_at_height(inp) - else: - return json.loads(make_request( - 'https://blockchain.info/rawblock/'+inp).decode("utf-8")) - - -def bci_get_block_header_data(inp): - j = _get_block(inp) - return { - 'version': j['ver'], - 'hash': j['hash'], - 'prevhash': j['prev_block'], - 'timestamp': j['time'], - 'merkle_root': j['mrkl_root'], - 'bits': j['bits'], - 'nonce': j['nonce'], - } - -def blockr_get_block_header_data(height, network='btc'): - if network == 'testnet': - blockr_url = "http://tbtc.blockr.io/api/v1/block/raw/" - elif network == 'btc': - blockr_url = "http://btc.blockr.io/api/v1/block/raw/" - else: - raise Exception( - 'Unsupported network {0} for blockr_get_block_header_data'.format(network)) - - k = json.loads(make_request(blockr_url + str(height)).decode("utf-8")) - j = k['data'] - return { - 'version': j['version'], - 'hash': j['hash'], - 'prevhash': j['previousblockhash'], - 'timestamp': j['time'], - 'merkle_root': j['merkleroot'], - 'bits': int(j['bits'], 16), - 'nonce': j['nonce'], - } - - -def get_block_timestamp(height, network='btc'): - if network == 'testnet': - blockr_url = "http://tbtc.blockr.io/api/v1/block/info/" - elif network == 'btc': - blockr_url = "http://btc.blockr.io/api/v1/block/info/" - else: - raise Exception( - 'Unsupported network {0} for get_block_timestamp'.format(network)) - - import time, calendar - if isinstance(height, list): - k = json.loads(make_request(blockr_url + ','.join([str(x) for x in height])).decode("utf-8")) - o = {x['nb']: calendar.timegm(time.strptime(x['time_utc'], - "%Y-%m-%dT%H:%M:%SZ")) for x in k['data']} - return [o[x] for x in height] - else: - k = json.loads(make_request(blockr_url + str(height)).decode("utf-8")) - j = k['data']['time_utc'] - return calendar.timegm(time.strptime(j, "%Y-%m-%dT%H:%M:%SZ")) - - -block_header_data_getters = { - 'bci': bci_get_block_header_data, - 'blockr': blockr_get_block_header_data -} - - -def get_block_header_data(inp, **kwargs): - f = block_header_data_getters.get(kwargs.get('source', ''), - bci_get_block_header_data) - return f(inp, **kwargs) - - -def get_txs_in_block(inp): - j = _get_block(inp) - hashes = [t['hash'] for t in j['tx']] - return hashes - - -def get_block_height(txhash): - j = json.loads(make_request('https://blockchain.info/rawtx/'+txhash).decode("utf-8")) - return j['block_height'] - -# fromAddr, toAddr, 12345, changeAddress -def get_tx_composite(inputs, outputs, output_value, change_address=None, network=None): - """mktx using blockcypher API""" - inputs = [inputs] if not isinstance(inputs, list) else inputs - outputs = [outputs] if not isinstance(outputs, list) else outputs - network = set_network(change_address or inputs) if not network else network.lower() - url = "http://api.blockcypher.com/v1/btc/{network}/txs/new?includeToSignTx=true".format( - network=('test3' if network=='testnet' else 'main')) - is_address = lambda a: bool(re.match("^[123mn][a-km-zA-HJ-NP-Z0-9]{26,33}$", a)) - if any([is_address(x) for x in inputs]): - inputs_type = 'addresses' # also accepts UTXOs, only addresses supported presently - if any([is_address(x) for x in outputs]): - outputs_type = 'addresses' # TODO: add UTXO support - data = { - 'inputs': [{inputs_type: inputs}], - 'confirmations': 0, - 'preference': 'high', - 'outputs': [{outputs_type: outputs, "value": output_value}] - } - if change_address: - data["change_address"] = change_address # - jdata = json.loads(make_request(url, data)) - hash, txh = jdata.get("tosign")[0], jdata.get("tosign_tx")[0] - assert bin_dbl_sha256(txh.decode('hex')).encode('hex') == hash, "checksum mismatch %s" % hash - return txh.encode("utf-8") - -blockcypher_mktx = get_tx_composite diff --git a/src/lib/pybitcointools/bitcoin/blocks.py b/src/lib/pybitcointools/bitcoin/blocks.py deleted file mode 100644 index 9df6b35c..00000000 --- a/src/lib/pybitcointools/bitcoin/blocks.py +++ /dev/null @@ -1,50 +0,0 @@ -from .main import * - - -def serialize_header(inp): - o = encode(inp['version'], 256, 4)[::-1] + \ - inp['prevhash'].decode('hex')[::-1] + \ - inp['merkle_root'].decode('hex')[::-1] + \ - encode(inp['timestamp'], 256, 4)[::-1] + \ - encode(inp['bits'], 256, 4)[::-1] + \ - encode(inp['nonce'], 256, 4)[::-1] - h = bin_sha256(bin_sha256(o))[::-1].encode('hex') - assert h == inp['hash'], (sha256(o), inp['hash']) - return o.encode('hex') - - -def deserialize_header(inp): - inp = inp.decode('hex') - return { - "version": decode(inp[:4][::-1], 256), - "prevhash": inp[4:36][::-1].encode('hex'), - "merkle_root": inp[36:68][::-1].encode('hex'), - "timestamp": decode(inp[68:72][::-1], 256), - "bits": decode(inp[72:76][::-1], 256), - "nonce": decode(inp[76:80][::-1], 256), - "hash": bin_sha256(bin_sha256(inp))[::-1].encode('hex') - } - - -def mk_merkle_proof(header, hashes, index): - nodes = [h.decode('hex')[::-1] for h in hashes] - if len(nodes) % 2 and len(nodes) > 2: - nodes.append(nodes[-1]) - layers = [nodes] - while len(nodes) > 1: - newnodes = [] - for i in range(0, len(nodes) - 1, 2): - newnodes.append(bin_sha256(bin_sha256(nodes[i] + nodes[i+1]))) - if len(newnodes) % 2 and len(newnodes) > 2: - newnodes.append(newnodes[-1]) - nodes = newnodes - layers.append(nodes) - # Sanity check, make sure merkle root is valid - assert nodes[0][::-1].encode('hex') == header['merkle_root'] - merkle_siblings = \ - [layers[i][(index >> i) ^ 1] for i in range(len(layers)-1)] - return { - "hash": hashes[index], - "siblings": [x[::-1].encode('hex') for x in merkle_siblings], - "header": header - } diff --git a/src/lib/pybitcointools/bitcoin/composite.py b/src/lib/pybitcointools/bitcoin/composite.py deleted file mode 100644 index e5d50492..00000000 --- a/src/lib/pybitcointools/bitcoin/composite.py +++ /dev/null @@ -1,128 +0,0 @@ -from .main import * -from .transaction import * -from .bci import * -from .deterministic import * -from .blocks import * - - -# Takes privkey, address, value (satoshis), fee (satoshis) -def send(frm, to, value, fee=10000, **kwargs): - return sendmultitx(frm, to + ":" + str(value), fee, **kwargs) - - -# Takes privkey, "address1:value1,address2:value2" (satoshis), fee (satoshis) -def sendmultitx(frm, *args, **kwargs): - tv, fee = args[:-1], int(args[-1]) - outs = [] - outvalue = 0 - for a in tv: - outs.append(a) - outvalue += int(a.split(":")[1]) - - u = unspent(privtoaddr(frm), **kwargs) - u2 = select(u, int(outvalue)+int(fee)) - argz = u2 + outs + [privtoaddr(frm), fee] - tx = mksend(*argz) - tx2 = signall(tx, frm) - return pushtx(tx2, **kwargs) - - -# Takes address, address, value (satoshis), fee(satoshis) -def preparetx(frm, to, value, fee=10000, **kwargs): - tovalues = to + ":" + str(value) - return preparemultitx(frm, tovalues, fee, **kwargs) - - -# Takes address, address:value, address:value ... (satoshis), fee(satoshis) -def preparemultitx(frm, *args, **kwargs): - tv, fee = args[:-1], int(args[-1]) - outs = [] - outvalue = 0 - for a in tv: - outs.append(a) - outvalue += int(a.split(":")[1]) - - u = unspent(frm, **kwargs) - u2 = select(u, int(outvalue)+int(fee)) - argz = u2 + outs + [frm, fee] - return mksend(*argz) - - -# BIP32 hierarchical deterministic multisig script -def bip32_hdm_script(*args): - if len(args) == 3: - keys, req, path = args - else: - i, keys, path = 0, [], [] - while len(args[i]) > 40: - keys.append(args[i]) - i += 1 - req = int(args[i]) - path = map(int, args[i+1:]) - pubs = sorted(map(lambda x: bip32_descend(x, path), keys)) - return mk_multisig_script(pubs, req) - - -# BIP32 hierarchical deterministic multisig address -def bip32_hdm_addr(*args): - return scriptaddr(bip32_hdm_script(*args)) - - -# Setup a coinvault transaction -def setup_coinvault_tx(tx, script): - txobj = deserialize(tx) - N = deserialize_script(script)[-2] - for inp in txobj["ins"]: - inp["script"] = serialize_script([None] * (N+1) + [script]) - return serialize(txobj) - - -# Sign a coinvault transaction -def sign_coinvault_tx(tx, priv): - pub = privtopub(priv) - txobj = deserialize(tx) - subscript = deserialize_script(txobj['ins'][0]['script']) - oscript = deserialize_script(subscript[-1]) - k, pubs = oscript[0], oscript[1:-2] - for j in range(len(txobj['ins'])): - scr = deserialize_script(txobj['ins'][j]['script']) - for i, p in enumerate(pubs): - if p == pub: - scr[i+1] = multisign(tx, j, subscript[-1], priv) - if len(filter(lambda x: x, scr[1:-1])) >= k: - scr = [None] + filter(lambda x: x, scr[1:-1])[:k] + [scr[-1]] - txobj['ins'][j]['script'] = serialize_script(scr) - return serialize(txobj) - - -# Inspects a transaction -def inspect(tx, **kwargs): - d = deserialize(tx) - isum = 0 - ins = {} - for _in in d['ins']: - h = _in['outpoint']['hash'] - i = _in['outpoint']['index'] - prevout = deserialize(fetchtx(h, **kwargs))['outs'][i] - isum += prevout['value'] - a = script_to_address(prevout['script']) - ins[a] = ins.get(a, 0) + prevout['value'] - outs = [] - osum = 0 - for _out in d['outs']: - outs.append({'address': script_to_address(_out['script']), - 'value': _out['value']}) - osum += _out['value'] - return { - 'fee': isum - osum, - 'outs': outs, - 'ins': ins - } - - -def merkle_prove(txhash): - blocknum = str(get_block_height(txhash)) - header = get_block_header_data(blocknum) - hashes = get_txs_in_block(blocknum) - i = hashes.index(txhash) - return mk_merkle_proof(header, hashes, i) diff --git a/src/lib/pybitcointools/bitcoin/deterministic.py b/src/lib/pybitcointools/bitcoin/deterministic.py deleted file mode 100644 index b2bdbbc6..00000000 --- a/src/lib/pybitcointools/bitcoin/deterministic.py +++ /dev/null @@ -1,199 +0,0 @@ -from .main import * -import hmac -import hashlib -from binascii import hexlify -# Electrum wallets - - -def electrum_stretch(seed): - return slowsha(seed) - -# Accepts seed or stretched seed, returns master public key - - -def electrum_mpk(seed): - if len(seed) == 32: - seed = electrum_stretch(seed) - return privkey_to_pubkey(seed)[2:] - -# Accepts (seed or stretched seed), index and secondary index -# (conventionally 0 for ordinary addresses, 1 for change) , returns privkey - - -def electrum_privkey(seed, n, for_change=0): - if len(seed) == 32: - seed = electrum_stretch(seed) - mpk = electrum_mpk(seed) - offset = dbl_sha256(from_int_representation_to_bytes(n)+b':'+from_int_representation_to_bytes(for_change)+b':'+binascii.unhexlify(mpk)) - return add_privkeys(seed, offset) - -# Accepts (seed or stretched seed or master pubkey), index and secondary index -# (conventionally 0 for ordinary addresses, 1 for change) , returns pubkey - - -def electrum_pubkey(masterkey, n, for_change=0): - if len(masterkey) == 32: - mpk = electrum_mpk(electrum_stretch(masterkey)) - elif len(masterkey) == 64: - mpk = electrum_mpk(masterkey) - else: - mpk = masterkey - bin_mpk = encode_pubkey(mpk, 'bin_electrum') - offset = bin_dbl_sha256(from_int_representation_to_bytes(n)+b':'+from_int_representation_to_bytes(for_change)+b':'+bin_mpk) - return add_pubkeys('04'+mpk, privtopub(offset)) - -# seed/stretched seed/pubkey -> address (convenience method) - - -def electrum_address(masterkey, n, for_change=0, version=0): - return pubkey_to_address(electrum_pubkey(masterkey, n, for_change), version) - -# Given a master public key, a private key from that wallet and its index, -# cracks the secret exponent which can be used to generate all other private -# keys in the wallet - - -def crack_electrum_wallet(mpk, pk, n, for_change=0): - bin_mpk = encode_pubkey(mpk, 'bin_electrum') - offset = dbl_sha256(str(n)+':'+str(for_change)+':'+bin_mpk) - return subtract_privkeys(pk, offset) - -# Below code ASSUMES binary inputs and compressed pubkeys -MAINNET_PRIVATE = b'\x04\x88\xAD\xE4' -MAINNET_PUBLIC = b'\x04\x88\xB2\x1E' -TESTNET_PRIVATE = b'\x04\x35\x83\x94' -TESTNET_PUBLIC = b'\x04\x35\x87\xCF' -PRIVATE = [MAINNET_PRIVATE, TESTNET_PRIVATE] -PUBLIC = [MAINNET_PUBLIC, TESTNET_PUBLIC] - -# BIP32 child key derivation - - -def raw_bip32_ckd(rawtuple, i): - vbytes, depth, fingerprint, oldi, chaincode, key = rawtuple - i = int(i) - - if vbytes in PRIVATE: - priv = key - pub = privtopub(key) - else: - pub = key - - if i >= 2**31: - if vbytes in PUBLIC: - raise Exception("Can't do private derivation on public key!") - I = hmac.new(chaincode, b'\x00'+priv[:32]+encode(i, 256, 4), hashlib.sha512).digest() - else: - I = hmac.new(chaincode, pub+encode(i, 256, 4), hashlib.sha512).digest() - - if vbytes in PRIVATE: - newkey = add_privkeys(I[:32]+B'\x01', priv) - fingerprint = bin_hash160(privtopub(key))[:4] - if vbytes in PUBLIC: - newkey = add_pubkeys(compress(privtopub(I[:32])), key) - fingerprint = bin_hash160(key)[:4] - - return (vbytes, depth + 1, fingerprint, i, I[32:], newkey) - - -def bip32_serialize(rawtuple): - vbytes, depth, fingerprint, i, chaincode, key = rawtuple - i = encode(i, 256, 4) - chaincode = encode(hash_to_int(chaincode), 256, 32) - keydata = b'\x00'+key[:-1] if vbytes in PRIVATE else key - bindata = vbytes + from_int_to_byte(depth % 256) + fingerprint + i + chaincode + keydata - return changebase(bindata+bin_dbl_sha256(bindata)[:4], 256, 58) - - -def bip32_deserialize(data): - dbin = changebase(data, 58, 256) - if bin_dbl_sha256(dbin[:-4])[:4] != dbin[-4:]: - raise Exception("Invalid checksum") - vbytes = dbin[0:4] - depth = from_byte_to_int(dbin[4]) - fingerprint = dbin[5:9] - i = decode(dbin[9:13], 256) - chaincode = dbin[13:45] - key = dbin[46:78]+b'\x01' if vbytes in PRIVATE else dbin[45:78] - return (vbytes, depth, fingerprint, i, chaincode, key) - - -def raw_bip32_privtopub(rawtuple): - vbytes, depth, fingerprint, i, chaincode, key = rawtuple - newvbytes = MAINNET_PUBLIC if vbytes == MAINNET_PRIVATE else TESTNET_PUBLIC - return (newvbytes, depth, fingerprint, i, chaincode, privtopub(key)) - - -def bip32_privtopub(data): - return bip32_serialize(raw_bip32_privtopub(bip32_deserialize(data))) - - -def bip32_ckd(data, i): - return bip32_serialize(raw_bip32_ckd(bip32_deserialize(data), i)) - - -def bip32_master_key(seed, vbytes=MAINNET_PRIVATE): - I = hmac.new(from_string_to_bytes("Bitcoin seed"), seed, hashlib.sha512).digest() - return bip32_serialize((vbytes, 0, b'\x00'*4, 0, I[32:], I[:32]+b'\x01')) - - -def bip32_bin_extract_key(data): - return bip32_deserialize(data)[-1] - - -def bip32_extract_key(data): - return safe_hexlify(bip32_deserialize(data)[-1]) - -# Exploits the same vulnerability as above in Electrum wallets -# Takes a BIP32 pubkey and one of the child privkeys of its corresponding -# privkey and returns the BIP32 privkey associated with that pubkey - - -def raw_crack_bip32_privkey(parent_pub, priv): - vbytes, depth, fingerprint, i, chaincode, key = priv - pvbytes, pdepth, pfingerprint, pi, pchaincode, pkey = parent_pub - i = int(i) - - if i >= 2**31: - raise Exception("Can't crack private derivation!") - - I = hmac.new(pchaincode, pkey+encode(i, 256, 4), hashlib.sha512).digest() - - pprivkey = subtract_privkeys(key, I[:32]+b'\x01') - - newvbytes = MAINNET_PRIVATE if vbytes == MAINNET_PUBLIC else TESTNET_PRIVATE - return (newvbytes, pdepth, pfingerprint, pi, pchaincode, pprivkey) - - -def crack_bip32_privkey(parent_pub, priv): - dsppub = bip32_deserialize(parent_pub) - dspriv = bip32_deserialize(priv) - return bip32_serialize(raw_crack_bip32_privkey(dsppub, dspriv)) - - -def coinvault_pub_to_bip32(*args): - if len(args) == 1: - args = args[0].split(' ') - vals = map(int, args[34:]) - I1 = ''.join(map(chr, vals[:33])) - I2 = ''.join(map(chr, vals[35:67])) - return bip32_serialize((MAINNET_PUBLIC, 0, b'\x00'*4, 0, I2, I1)) - - -def coinvault_priv_to_bip32(*args): - if len(args) == 1: - args = args[0].split(' ') - vals = map(int, args[34:]) - I2 = ''.join(map(chr, vals[35:67])) - I3 = ''.join(map(chr, vals[72:104])) - return bip32_serialize((MAINNET_PRIVATE, 0, b'\x00'*4, 0, I2, I3+b'\x01')) - - -def bip32_descend(*args): - if len(args) == 2 and isinstance(args[1], list): - key, path = args - else: - key, path = args[0], map(int, args[1:]) - for p in path: - key = bip32_ckd(key, p) - return bip32_extract_key(key) diff --git a/src/lib/pybitcointools/bitcoin/english.txt b/src/lib/pybitcointools/bitcoin/english.txt deleted file mode 100644 index 942040ed..00000000 --- a/src/lib/pybitcointools/bitcoin/english.txt +++ /dev/null @@ -1,2048 +0,0 @@ -abandon -ability -able -about -above -absent -absorb -abstract -absurd -abuse -access -accident -account -accuse -achieve -acid -acoustic -acquire -across -act -action -actor -actress -actual -adapt -add -addict -address -adjust -admit -adult -advance -advice -aerobic -affair -afford -afraid -again -age -agent -agree -ahead -aim -air -airport -aisle -alarm -album -alcohol -alert -alien -all -alley -allow -almost -alone -alpha -already -also -alter -always -amateur -amazing -among -amount -amused -analyst -anchor -ancient -anger -angle -angry -animal -ankle -announce -annual -another -answer -antenna -antique -anxiety -any -apart -apology -appear -apple -approve -april -arch -arctic -area -arena -argue -arm -armed -armor -army -around -arrange -arrest -arrive -arrow -art -artefact -artist -artwork -ask -aspect -assault -asset -assist -assume -asthma -athlete -atom -attack -attend -attitude -attract -auction -audit -august -aunt -author -auto -autumn -average -avocado -avoid -awake -aware -away -awesome -awful -awkward -axis -baby -bachelor -bacon -badge -bag -balance -balcony -ball -bamboo -banana -banner -bar -barely -bargain -barrel -base -basic -basket -battle -beach -bean -beauty -because -become -beef -before -begin -behave -behind -believe -below -belt -bench -benefit -best -betray -better -between -beyond -bicycle -bid -bike -bind -biology -bird -birth -bitter -black -blade -blame -blanket -blast -bleak -bless -blind -blood -blossom -blouse -blue -blur -blush -board -boat -body -boil -bomb -bone -bonus -book -boost -border -boring -borrow -boss -bottom -bounce -box -boy -bracket -brain -brand -brass -brave -bread -breeze -brick -bridge -brief -bright -bring -brisk -broccoli -broken -bronze -broom -brother -brown -brush -bubble -buddy -budget -buffalo -build -bulb -bulk -bullet -bundle -bunker -burden -burger -burst -bus -business -busy -butter -buyer -buzz -cabbage -cabin -cable -cactus -cage -cake -call -calm -camera -camp -can -canal -cancel -candy -cannon -canoe -canvas -canyon -capable -capital -captain -car -carbon -card -cargo -carpet -carry -cart -case -cash -casino -castle -casual -cat -catalog -catch -category -cattle -caught -cause -caution -cave -ceiling -celery -cement -census -century -cereal -certain -chair -chalk -champion -change -chaos -chapter -charge -chase -chat -cheap -check -cheese -chef -cherry -chest -chicken -chief -child -chimney -choice -choose -chronic -chuckle -chunk -churn -cigar -cinnamon -circle -citizen -city -civil -claim -clap -clarify -claw -clay -clean -clerk -clever -click -client -cliff -climb -clinic -clip -clock -clog -close -cloth -cloud -clown -club -clump -cluster -clutch -coach -coast -coconut -code -coffee -coil -coin -collect -color -column -combine -come -comfort -comic -common -company -concert -conduct -confirm -congress -connect -consider -control -convince -cook -cool -copper -copy -coral -core -corn -correct -cost -cotton -couch -country -couple -course -cousin -cover -coyote -crack -cradle -craft -cram -crane -crash -crater -crawl -crazy -cream -credit -creek -crew -cricket -crime -crisp -critic -crop -cross -crouch -crowd -crucial -cruel -cruise -crumble -crunch -crush -cry -crystal -cube -culture -cup -cupboard -curious -current -curtain -curve -cushion -custom -cute -cycle -dad -damage -damp -dance -danger -daring -dash -daughter -dawn -day -deal -debate -debris -decade -december -decide -decline -decorate -decrease -deer -defense -define -defy -degree -delay -deliver -demand -demise -denial -dentist -deny -depart -depend -deposit -depth -deputy -derive -describe -desert -design -desk -despair -destroy -detail -detect -develop -device -devote -diagram -dial -diamond -diary -dice -diesel -diet -differ -digital -dignity -dilemma -dinner -dinosaur -direct -dirt -disagree -discover -disease -dish -dismiss -disorder -display -distance -divert -divide -divorce -dizzy -doctor -document -dog -doll -dolphin -domain -donate -donkey -donor -door -dose -double -dove -draft -dragon -drama -drastic -draw -dream -dress -drift -drill -drink -drip -drive -drop -drum -dry -duck -dumb -dune -during -dust -dutch -duty -dwarf -dynamic -eager -eagle -early -earn -earth -easily -east -easy -echo -ecology -economy -edge -edit -educate -effort -egg -eight -either -elbow -elder -electric -elegant -element -elephant -elevator -elite -else -embark -embody -embrace -emerge -emotion -employ -empower -empty -enable -enact -end -endless -endorse -enemy -energy -enforce -engage -engine -enhance -enjoy -enlist -enough -enrich -enroll -ensure -enter -entire -entry -envelope -episode -equal -equip -era -erase -erode -erosion -error -erupt -escape -essay -essence -estate -eternal -ethics -evidence -evil -evoke -evolve -exact -example -excess -exchange -excite -exclude -excuse -execute -exercise -exhaust -exhibit -exile -exist -exit -exotic -expand -expect -expire -explain -expose -express -extend -extra -eye -eyebrow -fabric -face -faculty -fade -faint -faith -fall -false -fame -family -famous -fan -fancy -fantasy -farm -fashion -fat -fatal -father -fatigue -fault -favorite -feature -february -federal -fee -feed -feel -female -fence -festival -fetch -fever -few -fiber -fiction -field -figure -file -film -filter -final -find -fine -finger -finish -fire -firm -first -fiscal -fish -fit -fitness -fix -flag -flame -flash -flat -flavor -flee -flight -flip -float -flock -floor -flower -fluid -flush -fly -foam -focus -fog -foil -fold -follow -food -foot -force -forest -forget -fork -fortune -forum -forward -fossil -foster -found -fox -fragile -frame -frequent -fresh -friend -fringe -frog -front -frost -frown -frozen -fruit -fuel -fun -funny -furnace -fury -future -gadget -gain -galaxy -gallery -game -gap -garage -garbage -garden -garlic -garment -gas -gasp -gate -gather -gauge -gaze -general -genius -genre -gentle -genuine -gesture -ghost -giant -gift -giggle -ginger -giraffe -girl -give -glad -glance -glare -glass -glide -glimpse -globe -gloom -glory -glove -glow -glue -goat -goddess -gold -good -goose -gorilla -gospel -gossip -govern -gown -grab -grace -grain -grant -grape -grass -gravity -great -green -grid -grief -grit -grocery -group -grow -grunt -guard -guess -guide -guilt -guitar -gun -gym -habit -hair -half -hammer -hamster -hand -happy -harbor -hard -harsh -harvest -hat -have -hawk -hazard -head -health -heart -heavy -hedgehog -height -hello -helmet -help -hen -hero -hidden -high -hill -hint -hip -hire -history -hobby -hockey -hold -hole -holiday -hollow -home -honey -hood -hope -horn -horror -horse -hospital -host -hotel -hour -hover -hub -huge -human -humble -humor -hundred -hungry -hunt -hurdle -hurry -hurt -husband -hybrid -ice -icon -idea -identify -idle -ignore -ill -illegal -illness -image -imitate -immense -immune -impact -impose -improve -impulse -inch -include -income -increase -index -indicate -indoor -industry -infant -inflict -inform -inhale -inherit -initial -inject -injury -inmate -inner -innocent -input -inquiry -insane -insect -inside -inspire -install -intact -interest -into -invest -invite -involve -iron -island -isolate -issue -item -ivory -jacket -jaguar -jar -jazz -jealous -jeans -jelly -jewel -job -join -joke -journey -joy -judge -juice -jump -jungle -junior -junk -just -kangaroo -keen -keep -ketchup -key -kick -kid -kidney -kind -kingdom -kiss -kit -kitchen -kite -kitten -kiwi -knee -knife -knock -know -lab -label -labor -ladder -lady -lake -lamp -language -laptop -large -later -latin -laugh -laundry -lava -law -lawn -lawsuit -layer -lazy -leader -leaf -learn -leave -lecture -left -leg -legal -legend -leisure -lemon -lend -length -lens -leopard -lesson -letter -level -liar -liberty -library -license -life -lift -light -like -limb -limit -link -lion -liquid -list -little -live -lizard -load -loan -lobster -local -lock -logic -lonely -long -loop -lottery -loud -lounge -love -loyal -lucky -luggage -lumber -lunar -lunch -luxury -lyrics -machine -mad -magic -magnet -maid -mail -main -major -make -mammal -man -manage -mandate -mango -mansion -manual -maple -marble -march -margin -marine -market -marriage -mask -mass -master -match -material -math -matrix -matter -maximum -maze -meadow -mean -measure -meat -mechanic -medal -media -melody -melt -member -memory -mention -menu -mercy -merge -merit -merry -mesh -message -metal -method -middle -midnight -milk -million -mimic -mind -minimum -minor -minute -miracle -mirror -misery -miss -mistake -mix -mixed -mixture -mobile -model -modify -mom -moment -monitor -monkey -monster -month -moon -moral -more -morning -mosquito -mother -motion -motor -mountain -mouse -move -movie -much -muffin -mule -multiply -muscle -museum -mushroom -music -must -mutual -myself -mystery -myth -naive -name -napkin -narrow -nasty -nation -nature -near -neck -need -negative -neglect -neither -nephew -nerve -nest -net -network -neutral -never -news -next -nice -night -noble -noise -nominee -noodle -normal -north -nose -notable -note -nothing -notice -novel -now -nuclear -number -nurse -nut -oak -obey -object -oblige -obscure -observe -obtain -obvious -occur -ocean -october -odor -off -offer -office -often -oil -okay -old -olive -olympic -omit -once -one -onion -online -only -open -opera -opinion -oppose -option -orange -orbit -orchard -order -ordinary -organ -orient -original -orphan -ostrich -other -outdoor -outer -output -outside -oval -oven -over -own -owner -oxygen -oyster -ozone -pact -paddle -page -pair -palace -palm -panda -panel -panic -panther -paper -parade -parent -park -parrot -party -pass -patch -path -patient -patrol -pattern -pause -pave -payment -peace -peanut -pear -peasant -pelican -pen -penalty -pencil -people -pepper -perfect -permit -person -pet -phone -photo -phrase -physical -piano -picnic -picture -piece -pig -pigeon -pill -pilot -pink -pioneer -pipe -pistol -pitch -pizza -place -planet -plastic -plate -play -please -pledge -pluck -plug -plunge -poem -poet -point -polar -pole -police -pond -pony -pool -popular -portion -position -possible -post -potato -pottery -poverty -powder -power -practice -praise -predict -prefer -prepare -present -pretty -prevent -price -pride -primary -print -priority -prison -private -prize -problem -process -produce -profit -program -project -promote -proof -property -prosper -protect -proud -provide -public -pudding -pull -pulp -pulse -pumpkin -punch -pupil -puppy -purchase -purity -purpose -purse -push -put -puzzle -pyramid -quality -quantum -quarter -question -quick -quit -quiz -quote -rabbit -raccoon -race -rack -radar -radio -rail -rain -raise -rally -ramp -ranch -random -range -rapid -rare -rate -rather -raven -raw -razor -ready -real -reason -rebel -rebuild -recall -receive -recipe -record -recycle -reduce -reflect -reform -refuse -region -regret -regular -reject -relax -release -relief -rely -remain -remember -remind -remove -render -renew -rent -reopen -repair -repeat -replace -report -require -rescue -resemble -resist -resource -response -result -retire -retreat -return -reunion -reveal -review -reward -rhythm -rib -ribbon -rice -rich -ride -ridge -rifle -right -rigid -ring -riot -ripple -risk -ritual -rival -river -road -roast -robot -robust -rocket -romance -roof -rookie -room -rose -rotate -rough -round -route -royal -rubber -rude -rug -rule -run -runway -rural -sad -saddle -sadness -safe -sail -salad -salmon -salon -salt -salute -same -sample -sand -satisfy -satoshi -sauce -sausage -save -say -scale -scan -scare -scatter -scene -scheme -school -science -scissors -scorpion -scout -scrap -screen -script -scrub -sea -search -season -seat -second -secret -section -security -seed -seek -segment -select -sell -seminar -senior -sense -sentence -series -service -session -settle -setup -seven -shadow -shaft -shallow -share -shed -shell -sheriff -shield -shift -shine -ship -shiver -shock -shoe -shoot -shop -short -shoulder -shove -shrimp -shrug -shuffle -shy -sibling -sick -side -siege -sight -sign -silent -silk -silly -silver -similar -simple -since -sing -siren -sister -situate -six -size -skate -sketch -ski -skill -skin -skirt -skull -slab -slam -sleep -slender -slice -slide -slight -slim -slogan -slot -slow -slush -small -smart -smile -smoke -smooth -snack -snake -snap -sniff -snow -soap -soccer -social -sock -soda -soft -solar -soldier -solid -solution -solve -someone -song -soon -sorry -sort -soul -sound -soup -source -south -space -spare -spatial -spawn -speak -special -speed -spell -spend -sphere -spice -spider -spike -spin -spirit -split -spoil -sponsor -spoon -sport -spot -spray -spread -spring -spy -square -squeeze -squirrel -stable -stadium -staff -stage -stairs -stamp -stand -start -state -stay -steak -steel -stem -step -stereo -stick -still -sting -stock -stomach -stone -stool -story -stove -strategy -street -strike -strong -struggle -student -stuff -stumble -style -subject -submit -subway -success -such -sudden -suffer -sugar -suggest -suit -summer -sun -sunny -sunset -super -supply -supreme -sure -surface -surge -surprise -surround -survey -suspect -sustain -swallow -swamp -swap -swarm -swear -sweet -swift -swim -swing -switch -sword -symbol -symptom -syrup -system -table -tackle -tag -tail -talent -talk -tank -tape -target -task -taste -tattoo -taxi -teach -team -tell -ten -tenant -tennis -tent -term -test -text -thank -that -theme -then -theory -there -they -thing -this -thought -three -thrive -throw -thumb -thunder -ticket -tide -tiger -tilt -timber -time -tiny -tip -tired -tissue -title -toast -tobacco -today -toddler -toe -together -toilet -token -tomato -tomorrow -tone -tongue -tonight -tool -tooth -top -topic -topple -torch -tornado -tortoise -toss -total -tourist -toward -tower -town -toy -track -trade -traffic -tragic -train -transfer -trap -trash -travel -tray -treat -tree -trend -trial -tribe -trick -trigger -trim -trip -trophy -trouble -truck -true -truly -trumpet -trust -truth -try -tube -tuition -tumble -tuna -tunnel -turkey -turn -turtle -twelve -twenty -twice -twin -twist -two -type -typical -ugly -umbrella -unable -unaware -uncle -uncover -under -undo -unfair -unfold -unhappy -uniform -unique -unit -universe -unknown -unlock -until -unusual -unveil -update -upgrade -uphold -upon -upper -upset -urban -urge -usage -use -used -useful -useless -usual -utility -vacant -vacuum -vague -valid -valley -valve -van -vanish -vapor -various -vast -vault -vehicle -velvet -vendor -venture -venue -verb -verify -version -very -vessel -veteran -viable -vibrant -vicious -victory -video -view -village -vintage -violin -virtual -virus -visa -visit -visual -vital -vivid -vocal -voice -void -volcano -volume -vote -voyage -wage -wagon -wait -walk -wall -walnut -want -warfare -warm -warrior -wash -wasp -waste -water -wave -way -wealth -weapon -wear -weasel -weather -web -wedding -weekend -weird -welcome -west -wet -whale -what -wheat -wheel -when -where -whip -whisper -wide -width -wife -wild -will -win -window -wine -wing -wink -winner -winter -wire -wisdom -wise -wish -witness -wolf -woman -wonder -wood -wool -word -work -world -worry -worth -wrap -wreck -wrestle -wrist -write -wrong -yard -year -yellow -you -young -youth -zebra -zero -zone -zoo diff --git a/src/lib/pybitcointools/bitcoin/main.py b/src/lib/pybitcointools/bitcoin/main.py deleted file mode 100644 index 8cf3a9f7..00000000 --- a/src/lib/pybitcointools/bitcoin/main.py +++ /dev/null @@ -1,581 +0,0 @@ -#!/usr/bin/python -from .py2specials import * -from .py3specials import * -import binascii -import hashlib -import re -import sys -import os -import base64 -import time -import random -import hmac -from .ripemd import * - -# Elliptic curve parameters (secp256k1) - -P = 2**256 - 2**32 - 977 -N = 115792089237316195423570985008687907852837564279074904382605163141518161494337 -A = 0 -B = 7 -Gx = 55066263022277343669578718895168534326250603453777594175500187360389116729240 -Gy = 32670510020758816978083085130507043184471273380659243275938904335757337482424 -G = (Gx, Gy) - - -def change_curve(p, n, a, b, gx, gy): - global P, N, A, B, Gx, Gy, G - P, N, A, B, Gx, Gy = p, n, a, b, gx, gy - G = (Gx, Gy) - - -def getG(): - return G - -# Extended Euclidean Algorithm - - -def inv(a, n): - if a == 0: - return 0 - lm, hm = 1, 0 - low, high = a % n, n - while low > 1: - r = high//low - nm, new = hm-lm*r, high-low*r - lm, low, hm, high = nm, new, lm, low - return lm % n - - - -# JSON access (for pybtctool convenience) - - -def access(obj, prop): - if isinstance(obj, dict): - if prop in obj: - return obj[prop] - elif '.' in prop: - return obj[float(prop)] - else: - return obj[int(prop)] - else: - return obj[int(prop)] - - -def multiaccess(obj, prop): - return [access(o, prop) for o in obj] - - -def slice(obj, start=0, end=2**200): - return obj[int(start):int(end)] - - -def count(obj): - return len(obj) - -_sum = sum - - -def sum(obj): - return _sum(obj) - - -def isinf(p): - return p[0] == 0 and p[1] == 0 - - -def to_jacobian(p): - o = (p[0], p[1], 1) - return o - - -def jacobian_double(p): - if not p[1]: - return (0, 0, 0) - ysq = (p[1] ** 2) % P - S = (4 * p[0] * ysq) % P - M = (3 * p[0] ** 2 + A * p[2] ** 4) % P - nx = (M**2 - 2 * S) % P - ny = (M * (S - nx) - 8 * ysq ** 2) % P - nz = (2 * p[1] * p[2]) % P - return (nx, ny, nz) - - -def jacobian_add(p, q): - if not p[1]: - return q - if not q[1]: - return p - U1 = (p[0] * q[2] ** 2) % P - U2 = (q[0] * p[2] ** 2) % P - S1 = (p[1] * q[2] ** 3) % P - S2 = (q[1] * p[2] ** 3) % P - if U1 == U2: - if S1 != S2: - return (0, 0, 1) - return jacobian_double(p) - H = U2 - U1 - R = S2 - S1 - H2 = (H * H) % P - H3 = (H * H2) % P - U1H2 = (U1 * H2) % P - nx = (R ** 2 - H3 - 2 * U1H2) % P - ny = (R * (U1H2 - nx) - S1 * H3) % P - nz = (H * p[2] * q[2]) % P - return (nx, ny, nz) - - -def from_jacobian(p): - z = inv(p[2], P) - return ((p[0] * z**2) % P, (p[1] * z**3) % P) - - -def jacobian_multiply(a, n): - if a[1] == 0 or n == 0: - return (0, 0, 1) - if n == 1: - return a - if n < 0 or n >= N: - return jacobian_multiply(a, n % N) - if (n % 2) == 0: - return jacobian_double(jacobian_multiply(a, n//2)) - if (n % 2) == 1: - return jacobian_add(jacobian_double(jacobian_multiply(a, n//2)), a) - - -def fast_multiply(a, n): - return from_jacobian(jacobian_multiply(to_jacobian(a), n)) - - -def fast_add(a, b): - return from_jacobian(jacobian_add(to_jacobian(a), to_jacobian(b))) - -# Functions for handling pubkey and privkey formats - - -def get_pubkey_format(pub): - if is_python2: - two = '\x02' - three = '\x03' - four = '\x04' - else: - two = 2 - three = 3 - four = 4 - - if isinstance(pub, (tuple, list)): return 'decimal' - elif len(pub) == 65 and pub[0] == four: return 'bin' - elif len(pub) == 130 and pub[0:2] == '04': return 'hex' - elif len(pub) == 33 and pub[0] in [two, three]: return 'bin_compressed' - elif len(pub) == 66 and pub[0:2] in ['02', '03']: return 'hex_compressed' - elif len(pub) == 64: return 'bin_electrum' - elif len(pub) == 128: return 'hex_electrum' - else: raise Exception("Pubkey not in recognized format") - - -def encode_pubkey(pub, formt): - if not isinstance(pub, (tuple, list)): - pub = decode_pubkey(pub) - if formt == 'decimal': return pub - elif formt == 'bin': return b'\x04' + encode(pub[0], 256, 32) + encode(pub[1], 256, 32) - elif formt == 'bin_compressed': - return from_int_to_byte(2+(pub[1] % 2)) + encode(pub[0], 256, 32) - elif formt == 'hex': return '04' + encode(pub[0], 16, 64) + encode(pub[1], 16, 64) - elif formt == 'hex_compressed': - return '0'+str(2+(pub[1] % 2)) + encode(pub[0], 16, 64) - elif formt == 'bin_electrum': return encode(pub[0], 256, 32) + encode(pub[1], 256, 32) - elif formt == 'hex_electrum': return encode(pub[0], 16, 64) + encode(pub[1], 16, 64) - else: raise Exception("Invalid format!") - - -def decode_pubkey(pub, formt=None): - if not formt: formt = get_pubkey_format(pub) - if formt == 'decimal': return pub - elif formt == 'bin': return (decode(pub[1:33], 256), decode(pub[33:65], 256)) - elif formt == 'bin_compressed': - x = decode(pub[1:33], 256) - beta = pow(int(x*x*x+A*x+B), int((P+1)//4), int(P)) - y = (P-beta) if ((beta + from_byte_to_int(pub[0])) % 2) else beta - return (x, y) - elif formt == 'hex': return (decode(pub[2:66], 16), decode(pub[66:130], 16)) - elif formt == 'hex_compressed': - return decode_pubkey(safe_from_hex(pub), 'bin_compressed') - elif formt == 'bin_electrum': - return (decode(pub[:32], 256), decode(pub[32:64], 256)) - elif formt == 'hex_electrum': - return (decode(pub[:64], 16), decode(pub[64:128], 16)) - else: raise Exception("Invalid format!") - -def get_privkey_format(priv): - if isinstance(priv, int_types): return 'decimal' - elif len(priv) == 32: return 'bin' - elif len(priv) == 33: return 'bin_compressed' - elif len(priv) == 64: return 'hex' - elif len(priv) == 66: return 'hex_compressed' - else: - bin_p = b58check_to_bin(priv) - if len(bin_p) == 32: return 'wif' - elif len(bin_p) == 33: return 'wif_compressed' - else: raise Exception("WIF does not represent privkey") - -def encode_privkey(priv, formt, vbyte=0): - if not isinstance(priv, int_types): - return encode_privkey(decode_privkey(priv), formt, vbyte) - if formt == 'decimal': return priv - elif formt == 'bin': return encode(priv, 256, 32) - elif formt == 'bin_compressed': return encode(priv, 256, 32)+b'\x01' - elif formt == 'hex': return encode(priv, 16, 64) - elif formt == 'hex_compressed': return encode(priv, 16, 64)+'01' - elif formt == 'wif': - return bin_to_b58check(encode(priv, 256, 32), 128+int(vbyte)) - elif formt == 'wif_compressed': - return bin_to_b58check(encode(priv, 256, 32)+b'\x01', 128+int(vbyte)) - else: raise Exception("Invalid format!") - -def decode_privkey(priv,formt=None): - if not formt: formt = get_privkey_format(priv) - if formt == 'decimal': return priv - elif formt == 'bin': return decode(priv, 256) - elif formt == 'bin_compressed': return decode(priv[:32], 256) - elif formt == 'hex': return decode(priv, 16) - elif formt == 'hex_compressed': return decode(priv[:64], 16) - elif formt == 'wif': return decode(b58check_to_bin(priv),256) - elif formt == 'wif_compressed': - return decode(b58check_to_bin(priv)[:32],256) - else: raise Exception("WIF does not represent privkey") - -def add_pubkeys(p1, p2): - f1, f2 = get_pubkey_format(p1), get_pubkey_format(p2) - return encode_pubkey(fast_add(decode_pubkey(p1, f1), decode_pubkey(p2, f2)), f1) - -def add_privkeys(p1, p2): - f1, f2 = get_privkey_format(p1), get_privkey_format(p2) - return encode_privkey((decode_privkey(p1, f1) + decode_privkey(p2, f2)) % N, f1) - -def mul_privkeys(p1, p2): - f1, f2 = get_privkey_format(p1), get_privkey_format(p2) - return encode_privkey((decode_privkey(p1, f1) * decode_privkey(p2, f2)) % N, f1) - -def multiply(pubkey, privkey): - f1, f2 = get_pubkey_format(pubkey), get_privkey_format(privkey) - pubkey, privkey = decode_pubkey(pubkey, f1), decode_privkey(privkey, f2) - # http://safecurves.cr.yp.to/twist.html - if not isinf(pubkey) and (pubkey[0]**3+B-pubkey[1]*pubkey[1]) % P != 0: - raise Exception("Point not on curve") - return encode_pubkey(fast_multiply(pubkey, privkey), f1) - - -def divide(pubkey, privkey): - factor = inv(decode_privkey(privkey), N) - return multiply(pubkey, factor) - - -def compress(pubkey): - f = get_pubkey_format(pubkey) - if 'compressed' in f: return pubkey - elif f == 'bin': return encode_pubkey(decode_pubkey(pubkey, f), 'bin_compressed') - elif f == 'hex' or f == 'decimal': - return encode_pubkey(decode_pubkey(pubkey, f), 'hex_compressed') - - -def decompress(pubkey): - f = get_pubkey_format(pubkey) - if 'compressed' not in f: return pubkey - elif f == 'bin_compressed': return encode_pubkey(decode_pubkey(pubkey, f), 'bin') - elif f == 'hex_compressed' or f == 'decimal': - return encode_pubkey(decode_pubkey(pubkey, f), 'hex') - - -def privkey_to_pubkey(privkey): - f = get_privkey_format(privkey) - privkey = decode_privkey(privkey, f) - if privkey >= N: - raise Exception("Invalid privkey") - if f in ['bin', 'bin_compressed', 'hex', 'hex_compressed', 'decimal']: - return encode_pubkey(fast_multiply(G, privkey), f) - else: - return encode_pubkey(fast_multiply(G, privkey), f.replace('wif', 'hex')) - -privtopub = privkey_to_pubkey - - -def privkey_to_address(priv, magicbyte=0): - return pubkey_to_address(privkey_to_pubkey(priv), magicbyte) -privtoaddr = privkey_to_address - - -def neg_pubkey(pubkey): - f = get_pubkey_format(pubkey) - pubkey = decode_pubkey(pubkey, f) - return encode_pubkey((pubkey[0], (P-pubkey[1]) % P), f) - - -def neg_privkey(privkey): - f = get_privkey_format(privkey) - privkey = decode_privkey(privkey, f) - return encode_privkey((N - privkey) % N, f) - -def subtract_pubkeys(p1, p2): - f1, f2 = get_pubkey_format(p1), get_pubkey_format(p2) - k2 = decode_pubkey(p2, f2) - return encode_pubkey(fast_add(decode_pubkey(p1, f1), (k2[0], (P - k2[1]) % P)), f1) - - -def subtract_privkeys(p1, p2): - f1, f2 = get_privkey_format(p1), get_privkey_format(p2) - k2 = decode_privkey(p2, f2) - return encode_privkey((decode_privkey(p1, f1) - k2) % N, f1) - -# Hashes - - -def bin_hash160(string): - intermed = hashlib.sha256(string).digest() - digest = '' - try: - digest = hashlib.new('ripemd160', intermed).digest() - except: - digest = RIPEMD160(intermed).digest() - return digest - - -def hash160(string): - return safe_hexlify(bin_hash160(string)) - - -def bin_sha256(string): - binary_data = string if isinstance(string, bytes) else bytes(string, 'utf-8') - return hashlib.sha256(binary_data).digest() - -def sha256(string): - return bytes_to_hex_string(bin_sha256(string)) - - -def bin_ripemd160(string): - try: - digest = hashlib.new('ripemd160', string).digest() - except: - digest = RIPEMD160(string).digest() - return digest - - -def ripemd160(string): - return safe_hexlify(bin_ripemd160(string)) - - -def bin_dbl_sha256(s): - bytes_to_hash = from_string_to_bytes(s) - return hashlib.sha256(hashlib.sha256(bytes_to_hash).digest()).digest() - - -def dbl_sha256(string): - return safe_hexlify(bin_dbl_sha256(string)) - - -def bin_slowsha(string): - string = from_string_to_bytes(string) - orig_input = string - for i in range(100000): - string = hashlib.sha256(string + orig_input).digest() - return string - - -def slowsha(string): - return safe_hexlify(bin_slowsha(string)) - - -def hash_to_int(x): - if len(x) in [40, 64]: - return decode(x, 16) - return decode(x, 256) - - -def num_to_var_int(x): - x = int(x) - if x < 253: return from_int_to_byte(x) - elif x < 65536: return from_int_to_byte(253)+encode(x, 256, 2)[::-1] - elif x < 4294967296: return from_int_to_byte(254) + encode(x, 256, 4)[::-1] - else: return from_int_to_byte(255) + encode(x, 256, 8)[::-1] - - -# WTF, Electrum? -def electrum_sig_hash(message): - padded = b"\x18Bitcoin Signed Message:\n" + num_to_var_int(len(message)) + from_string_to_bytes(message) - return bin_dbl_sha256(padded) - - -def random_key(): - # Gotta be secure after that java.SecureRandom fiasco... - entropy = random_string(32) \ - + str(random.randrange(2**256)) \ - + str(int(time.time() * 1000000)) - return sha256(entropy) - - -def random_electrum_seed(): - entropy = os.urandom(32) \ - + str(random.randrange(2**256)) \ - + str(int(time.time() * 1000000)) - return sha256(entropy)[:32] - -# Encodings - -def b58check_to_bin(inp): - leadingzbytes = len(re.match('^1*', inp).group(0)) - data = b'\x00' * leadingzbytes + changebase(inp, 58, 256) - assert bin_dbl_sha256(data[:-4])[:4] == data[-4:] - return data[1:-4] - - -def get_version_byte(inp): - leadingzbytes = len(re.match('^1*', inp).group(0)) - data = b'\x00' * leadingzbytes + changebase(inp, 58, 256) - assert bin_dbl_sha256(data[:-4])[:4] == data[-4:] - return ord(data[0]) - - -def hex_to_b58check(inp, magicbyte=0): - return bin_to_b58check(binascii.unhexlify(inp), magicbyte) - - -def b58check_to_hex(inp): - return safe_hexlify(b58check_to_bin(inp)) - - -def pubkey_to_address(pubkey, magicbyte=0): - if isinstance(pubkey, (list, tuple)): - pubkey = encode_pubkey(pubkey, 'bin') - if len(pubkey) in [66, 130]: - return bin_to_b58check( - bin_hash160(binascii.unhexlify(pubkey)), magicbyte) - return bin_to_b58check(bin_hash160(pubkey), magicbyte) - -pubtoaddr = pubkey_to_address - - -def is_privkey(priv): - try: - get_privkey_format(priv) - return True - except: - return False - -def is_pubkey(pubkey): - try: - get_pubkey_format(pubkey) - return True - except: - return False - -def is_address(addr): - ADDR_RE = re.compile("^[123mn][a-km-zA-HJ-NP-Z0-9]{26,33}$") - return bool(ADDR_RE.match(addr)) - - -# EDCSA - - -def encode_sig(v, r, s): - vb, rb, sb = from_int_to_byte(v), encode(r, 256), encode(s, 256) - - result = base64.b64encode(vb+b'\x00'*(32-len(rb))+rb+b'\x00'*(32-len(sb))+sb) - return result if is_python2 else str(result, 'utf-8') - - -def decode_sig(sig): - bytez = base64.b64decode(sig) - return from_byte_to_int(bytez[0]), decode(bytez[1:33], 256), decode(bytez[33:], 256) - -# https://tools.ietf.org/html/rfc6979#section-3.2 - - -def deterministic_generate_k(msghash, priv): - v = b'\x01' * 32 - k = b'\x00' * 32 - priv = encode_privkey(priv, 'bin') - msghash = encode(hash_to_int(msghash), 256, 32) - k = hmac.new(k, v+b'\x00'+priv+msghash, hashlib.sha256).digest() - v = hmac.new(k, v, hashlib.sha256).digest() - k = hmac.new(k, v+b'\x01'+priv+msghash, hashlib.sha256).digest() - v = hmac.new(k, v, hashlib.sha256).digest() - return decode(hmac.new(k, v, hashlib.sha256).digest(), 256) - - -def ecdsa_raw_sign(msghash, priv): - - z = hash_to_int(msghash) - k = deterministic_generate_k(msghash, priv) - - r, y = fast_multiply(G, k) - s = inv(k, N) * (z + r*decode_privkey(priv)) % N - - v, r, s = 27+((y % 2) ^ (0 if s * 2 < N else 1)), r, s if s * 2 < N else N - s - if 'compressed' in get_privkey_format(priv): - v += 4 - return v, r, s - - -def ecdsa_sign(msg, priv): - v, r, s = ecdsa_raw_sign(electrum_sig_hash(msg), priv) - sig = encode_sig(v, r, s) - assert ecdsa_verify(msg, sig, - privtopub(priv)), "Bad Sig!\t %s\nv = %d\n,r = %d\ns = %d" % (sig, v, r, s) - return sig - - -def ecdsa_raw_verify(msghash, vrs, pub): - v, r, s = vrs - if not (27 <= v <= 34): - return False - - w = inv(s, N) - z = hash_to_int(msghash) - - u1, u2 = z*w % N, r*w % N - x, y = fast_add(fast_multiply(G, u1), fast_multiply(decode_pubkey(pub), u2)) - return bool(r == x and (r % N) and (s % N)) - - -# For BitcoinCore, (msg = addr or msg = "") be default -def ecdsa_verify_addr(msg, sig, addr): - assert is_address(addr) - Q = ecdsa_recover(msg, sig) - magic = get_version_byte(addr) - return (addr == pubtoaddr(Q, int(magic))) or (addr == pubtoaddr(compress(Q), int(magic))) - - -def ecdsa_verify(msg, sig, pub): - if is_address(pub): - return ecdsa_verify_addr(msg, sig, pub) - return ecdsa_raw_verify(electrum_sig_hash(msg), decode_sig(sig), pub) - - -def ecdsa_raw_recover(msghash, vrs): - v, r, s = vrs - if not (27 <= v <= 34): - raise ValueError("%d must in range 27-31" % v) - x = r - xcubedaxb = (x*x*x+A*x+B) % P - beta = pow(xcubedaxb, (P+1)//4, P) - y = beta if v % 2 ^ beta % 2 else (P - beta) - # If xcubedaxb is not a quadratic residue, then r cannot be the x coord - # for a point on the curve, and so the sig is invalid - if (xcubedaxb - y*y) % P != 0 or not (r % N) or not (s % N): - return False - z = hash_to_int(msghash) - Gz = jacobian_multiply((Gx, Gy, 1), (N - z) % N) - XY = jacobian_multiply((x, y, 1), s) - Qr = jacobian_add(Gz, XY) - Q = jacobian_multiply(Qr, inv(r, N)) - Q = from_jacobian(Q) - - # if ecdsa_raw_verify(msghash, vrs, Q): - return Q - # return False - - -def ecdsa_recover(msg, sig): - v,r,s = decode_sig(sig) - Q = ecdsa_raw_recover(electrum_sig_hash(msg), (v,r,s)) - return encode_pubkey(Q, 'hex_compressed') if v >= 31 else encode_pubkey(Q, 'hex') diff --git a/src/lib/pybitcointools/bitcoin/mnemonic.py b/src/lib/pybitcointools/bitcoin/mnemonic.py deleted file mode 100644 index a9df3617..00000000 --- a/src/lib/pybitcointools/bitcoin/mnemonic.py +++ /dev/null @@ -1,127 +0,0 @@ -import hashlib -import os.path -import binascii -import random -from bisect import bisect_left - -wordlist_english=list(open(os.path.join(os.path.dirname(os.path.realpath(__file__)),'english.txt'),'r')) - -def eint_to_bytes(entint,entbits): - a=hex(entint)[2:].rstrip('L').zfill(32) - print(a) - return binascii.unhexlify(a) - -def mnemonic_int_to_words(mint,mint_num_words,wordlist=wordlist_english): - backwords=[wordlist[(mint >> (11*x)) & 0x7FF].strip() for x in range(mint_num_words)] - return backwords[::-1] - -def entropy_cs(entbytes): - entropy_size=8*len(entbytes) - checksum_size=entropy_size//32 - hd=hashlib.sha256(entbytes).hexdigest() - csint=int(hd,16) >> (256-checksum_size) - return csint,checksum_size - -def entropy_to_words(entbytes,wordlist=wordlist_english): - if(len(entbytes) < 4 or len(entbytes) % 4 != 0): - raise ValueError("The size of the entropy must be a multiple of 4 bytes (multiple of 32 bits)") - entropy_size=8*len(entbytes) - csint,checksum_size = entropy_cs(entbytes) - entint=int(binascii.hexlify(entbytes),16) - mint=(entint << checksum_size) | csint - mint_num_words=(entropy_size+checksum_size)//11 - - return mnemonic_int_to_words(mint,mint_num_words,wordlist) - -def words_bisect(word,wordlist=wordlist_english): - lo=bisect_left(wordlist,word) - hi=len(wordlist)-bisect_left(wordlist[:lo:-1],word) - - return lo,hi - -def words_split(wordstr,wordlist=wordlist_english): - def popword(wordstr,wordlist): - for fwl in range(1,9): - w=wordstr[:fwl].strip() - lo,hi=words_bisect(w,wordlist) - if(hi-lo == 1): - return w,wordstr[fwl:].lstrip() - wordlist=wordlist[lo:hi] - raise Exception("Wordstr %s not found in list" %(w)) - - words=[] - tail=wordstr - while(len(tail)): - head,tail=popword(tail,wordlist) - words.append(head) - return words - -def words_to_mnemonic_int(words,wordlist=wordlist_english): - if(isinstance(words,str)): - words=words_split(words,wordlist) - return sum([wordlist.index(w) << (11*x) for x,w in enumerate(words[::-1])]) - -def words_verify(words,wordlist=wordlist_english): - if(isinstance(words,str)): - words=words_split(words,wordlist) - - mint = words_to_mnemonic_int(words,wordlist) - mint_bits=len(words)*11 - cs_bits=mint_bits//32 - entropy_bits=mint_bits-cs_bits - eint=mint >> cs_bits - csint=mint & ((1 << cs_bits)-1) - ebytes=_eint_to_bytes(eint,entropy_bits) - return csint == entropy_cs(ebytes) - -def mnemonic_to_seed(mnemonic_phrase,passphrase=b''): - try: - from hashlib import pbkdf2_hmac - def pbkdf2_hmac_sha256(password,salt,iters=2048): - return pbkdf2_hmac(hash_name='sha512',password=password,salt=salt,iterations=iters) - except: - try: - from Crypto.Protocol.KDF import PBKDF2 - from Crypto.Hash import SHA512,HMAC - - def pbkdf2_hmac_sha256(password,salt,iters=2048): - return PBKDF2(password=password,salt=salt,dkLen=64,count=iters,prf=lambda p,s: HMAC.new(p,s,SHA512).digest()) - except: - try: - - from pbkdf2 import PBKDF2 - import hmac - def pbkdf2_hmac_sha256(password,salt,iters=2048): - return PBKDF2(password,salt, iterations=iters, macmodule=hmac, digestmodule=hashlib.sha512).read(64) - except: - raise RuntimeError("No implementation of pbkdf2 was found!") - - return pbkdf2_hmac_sha256(password=mnemonic_phrase,salt=b'mnemonic'+passphrase) - -def words_mine(prefix,entbits,satisfunction,wordlist=wordlist_english,randombits=random.getrandbits): - prefix_bits=len(prefix)*11 - mine_bits=entbits-prefix_bits - pint=words_to_mnemonic_int(prefix,wordlist) - pint<<=mine_bits - dint=randombits(mine_bits) - count=0 - while(not satisfunction(entropy_to_words(eint_to_bytes(pint+dint,entbits)))): - dint=randombits(mine_bits) - if((count & 0xFFFF) == 0): - print("Searched %f percent of the space" % (float(count)/float(1 << mine_bits))) - - return entropy_to_words(eint_to_bytes(pint+dint,entbits)) - -if __name__=="__main__": - import json - testvectors=json.load(open('vectors.json','r')) - passed=True - for v in testvectors['english']: - ebytes=binascii.unhexlify(v[0]) - w=' '.join(entropy_to_words(ebytes)) - seed=mnemonic_to_seed(w,passphrase='TREZOR') - passed = passed and w==v[1] - passed = passed and binascii.hexlify(seed)==v[2] - print("Tests %s." % ("Passed" if passed else "Failed")) - - diff --git a/src/lib/pybitcointools/bitcoin/py2specials.py b/src/lib/pybitcointools/bitcoin/py2specials.py deleted file mode 100644 index 337154f3..00000000 --- a/src/lib/pybitcointools/bitcoin/py2specials.py +++ /dev/null @@ -1,98 +0,0 @@ -import sys, re -import binascii -import os -import hashlib - - -if sys.version_info.major == 2: - string_types = (str, unicode) - string_or_bytes_types = string_types - int_types = (int, float, long) - - # Base switching - code_strings = { - 2: '01', - 10: '0123456789', - 16: '0123456789abcdef', - 32: 'abcdefghijklmnopqrstuvwxyz234567', - 58: '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz', - 256: ''.join([chr(x) for x in range(256)]) - } - - def bin_dbl_sha256(s): - bytes_to_hash = from_string_to_bytes(s) - return hashlib.sha256(hashlib.sha256(bytes_to_hash).digest()).digest() - - def lpad(msg, symbol, length): - if len(msg) >= length: - return msg - return symbol * (length - len(msg)) + msg - - def get_code_string(base): - if base in code_strings: - return code_strings[base] - else: - raise ValueError("Invalid base!") - - def changebase(string, frm, to, minlen=0): - if frm == to: - return lpad(string, get_code_string(frm)[0], minlen) - return encode(decode(string, frm), to, minlen) - - def bin_to_b58check(inp, magicbyte=0): - if magicbyte == 0: - inp = '\x00' + inp - while magicbyte > 0: - inp = chr(int(magicbyte % 256)) + inp - magicbyte //= 256 - leadingzbytes = len(re.match('^\x00*', inp).group(0)) - checksum = bin_dbl_sha256(inp)[:4] - return '1' * leadingzbytes + changebase(inp+checksum, 256, 58) - - def bytes_to_hex_string(b): - return b.encode('hex') - - def safe_from_hex(s): - return s.decode('hex') - - def from_int_representation_to_bytes(a): - return str(a) - - def from_int_to_byte(a): - return chr(a) - - def from_byte_to_int(a): - return ord(a) - - def from_bytes_to_string(s): - return s - - def from_string_to_bytes(a): - return a - - def safe_hexlify(a): - return binascii.hexlify(a) - - def encode(val, base, minlen=0): - base, minlen = int(base), int(minlen) - code_string = get_code_string(base) - result = "" - while val > 0: - result = code_string[val % base] + result - val //= base - return code_string[0] * max(minlen - len(result), 0) + result - - def decode(string, base): - base = int(base) - code_string = get_code_string(base) - result = 0 - if base == 16: - string = string.lower() - while len(string) > 0: - result *= base - result += code_string.find(string[0]) - string = string[1:] - return result - - def random_string(x): - return os.urandom(x) diff --git a/src/lib/pybitcointools/bitcoin/py3specials.py b/src/lib/pybitcointools/bitcoin/py3specials.py deleted file mode 100644 index 7593b9a6..00000000 --- a/src/lib/pybitcointools/bitcoin/py3specials.py +++ /dev/null @@ -1,123 +0,0 @@ -import sys, os -import binascii -import hashlib - - -if sys.version_info.major == 3: - string_types = (str) - string_or_bytes_types = (str, bytes) - int_types = (int, float) - # Base switching - code_strings = { - 2: '01', - 10: '0123456789', - 16: '0123456789abcdef', - 32: 'abcdefghijklmnopqrstuvwxyz234567', - 58: '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz', - 256: ''.join([chr(x) for x in range(256)]) - } - - def bin_dbl_sha256(s): - bytes_to_hash = from_string_to_bytes(s) - return hashlib.sha256(hashlib.sha256(bytes_to_hash).digest()).digest() - - def lpad(msg, symbol, length): - if len(msg) >= length: - return msg - return symbol * (length - len(msg)) + msg - - def get_code_string(base): - if base in code_strings: - return code_strings[base] - else: - raise ValueError("Invalid base!") - - def changebase(string, frm, to, minlen=0): - if frm == to: - return lpad(string, get_code_string(frm)[0], minlen) - return encode(decode(string, frm), to, minlen) - - def bin_to_b58check(inp, magicbyte=0): - if magicbyte == 0: - inp = from_int_to_byte(0) + inp - while magicbyte > 0: - inp = from_int_to_byte(magicbyte % 256) + inp - magicbyte //= 256 - - leadingzbytes = 0 - for x in inp: - if x != 0: - break - leadingzbytes += 1 - - checksum = bin_dbl_sha256(inp)[:4] - return '1' * leadingzbytes + changebase(inp+checksum, 256, 58) - - def bytes_to_hex_string(b): - if isinstance(b, str): - return b - - return ''.join('{:02x}'.format(y) for y in b) - - def safe_from_hex(s): - return bytes.fromhex(s) - - def from_int_representation_to_bytes(a): - return bytes(str(a), 'utf-8') - - def from_int_to_byte(a): - return bytes([a]) - - def from_byte_to_int(a): - return a - - def from_string_to_bytes(a): - return a if isinstance(a, bytes) else bytes(a, 'utf-8') - - def safe_hexlify(a): - return str(binascii.hexlify(a), 'utf-8') - - def encode(val, base, minlen=0): - base, minlen = int(base), int(minlen) - code_string = get_code_string(base) - result_bytes = bytes() - while val > 0: - curcode = code_string[val % base] - result_bytes = bytes([ord(curcode)]) + result_bytes - val //= base - - pad_size = minlen - len(result_bytes) - - padding_element = b'\x00' if base == 256 else b'1' \ - if base == 58 else b'0' - if (pad_size > 0): - result_bytes = padding_element*pad_size + result_bytes - - result_string = ''.join([chr(y) for y in result_bytes]) - result = result_bytes if base == 256 else result_string - - return result - - def decode(string, base): - if base == 256 and isinstance(string, str): - string = bytes(bytearray.fromhex(string)) - base = int(base) - code_string = get_code_string(base) - result = 0 - if base == 256: - def extract(d, cs): - return d - else: - def extract(d, cs): - return cs.find(d if isinstance(d, str) else chr(d)) - - if base == 16: - string = string.lower() - while len(string) > 0: - result *= base - result += extract(string[0], code_string) - string = string[1:] - return result - - def random_string(x): - return str(os.urandom(x)) diff --git a/src/lib/pybitcointools/bitcoin/ripemd.py b/src/lib/pybitcointools/bitcoin/ripemd.py deleted file mode 100644 index 4b0c6045..00000000 --- a/src/lib/pybitcointools/bitcoin/ripemd.py +++ /dev/null @@ -1,414 +0,0 @@ -## ripemd.py - pure Python implementation of the RIPEMD-160 algorithm. -## Bjorn Edstrom 16 december 2007. -## -## Copyrights -## ========== -## -## This code is a derived from an implementation by Markus Friedl which is -## subject to the following license. This Python implementation is not -## subject to any other license. -## -##/* -## * Copyright (c) 2001 Markus Friedl. All rights reserved. -## * -## * Redistribution and use in source and binary forms, with or without -## * modification, are permitted provided that the following conditions -## * are met: -## * 1. Redistributions of source code must retain the above copyright -## * notice, this list of conditions and the following disclaimer. -## * 2. Redistributions in binary form must reproduce the above copyright -## * notice, this list of conditions and the following disclaimer in the -## * documentation and/or other materials provided with the distribution. -## * -## * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -## * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -## * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -## * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -## * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -## * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -## * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -## * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -## * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -## * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -## */ -##/* -## * Preneel, Bosselaers, Dobbertin, "The Cryptographic Hash Function RIPEMD-160", -## * RSA Laboratories, CryptoBytes, Volume 3, Number 2, Autumn 1997, -## * ftp://ftp.rsasecurity.com/pub/cryptobytes/crypto3n2.pdf -## */ - -try: - import psyco - psyco.full() -except ImportError: - pass - -import sys - -is_python2 = sys.version_info.major == 2 -#block_size = 1 -digest_size = 20 -digestsize = 20 - -try: - range = xrange -except: - pass - -class RIPEMD160: - """Return a new RIPEMD160 object. An optional string argument - may be provided; if present, this string will be automatically - hashed.""" - - def __init__(self, arg=None): - self.ctx = RMDContext() - if arg: - self.update(arg) - self.dig = None - - def update(self, arg): - """update(arg)""" - RMD160Update(self.ctx, arg, len(arg)) - self.dig = None - - def digest(self): - """digest()""" - if self.dig: - return self.dig - ctx = self.ctx.copy() - self.dig = RMD160Final(self.ctx) - self.ctx = ctx - return self.dig - - def hexdigest(self): - """hexdigest()""" - dig = self.digest() - hex_digest = '' - for d in dig: - if (is_python2): - hex_digest += '%02x' % ord(d) - else: - hex_digest += '%02x' % d - return hex_digest - - def copy(self): - """copy()""" - import copy - return copy.deepcopy(self) - - - -def new(arg=None): - """Return a new RIPEMD160 object. An optional string argument - may be provided; if present, this string will be automatically - hashed.""" - return RIPEMD160(arg) - - - -# -# Private. -# - -class RMDContext: - def __init__(self): - self.state = [0x67452301, 0xEFCDAB89, 0x98BADCFE, - 0x10325476, 0xC3D2E1F0] # uint32 - self.count = 0 # uint64 - self.buffer = [0]*64 # uchar - def copy(self): - ctx = RMDContext() - ctx.state = self.state[:] - ctx.count = self.count - ctx.buffer = self.buffer[:] - return ctx - -K0 = 0x00000000 -K1 = 0x5A827999 -K2 = 0x6ED9EBA1 -K3 = 0x8F1BBCDC -K4 = 0xA953FD4E - -KK0 = 0x50A28BE6 -KK1 = 0x5C4DD124 -KK2 = 0x6D703EF3 -KK3 = 0x7A6D76E9 -KK4 = 0x00000000 - -def ROL(n, x): - return ((x << n) & 0xffffffff) | (x >> (32 - n)) - -def F0(x, y, z): - return x ^ y ^ z - -def F1(x, y, z): - return (x & y) | (((~x) % 0x100000000) & z) - -def F2(x, y, z): - return (x | ((~y) % 0x100000000)) ^ z - -def F3(x, y, z): - return (x & z) | (((~z) % 0x100000000) & y) - -def F4(x, y, z): - return x ^ (y | ((~z) % 0x100000000)) - -def R(a, b, c, d, e, Fj, Kj, sj, rj, X): - a = ROL(sj, (a + Fj(b, c, d) + X[rj] + Kj) % 0x100000000) + e - c = ROL(10, c) - return a % 0x100000000, c - -PADDING = [0x80] + [0]*63 - -import sys -import struct - -def RMD160Transform(state, block): #uint32 state[5], uchar block[64] - x = [0]*16 - if sys.byteorder == 'little': - if is_python2: - x = struct.unpack('<16L', ''.join([chr(x) for x in block[0:64]])) - else: - x = struct.unpack('<16L', bytes(block[0:64])) - else: - raise "Error!!" - a = state[0] - b = state[1] - c = state[2] - d = state[3] - e = state[4] - - #/* Round 1 */ - a, c = R(a, b, c, d, e, F0, K0, 11, 0, x); - e, b = R(e, a, b, c, d, F0, K0, 14, 1, x); - d, a = R(d, e, a, b, c, F0, K0, 15, 2, x); - c, e = R(c, d, e, a, b, F0, K0, 12, 3, x); - b, d = R(b, c, d, e, a, F0, K0, 5, 4, x); - a, c = R(a, b, c, d, e, F0, K0, 8, 5, x); - e, b = R(e, a, b, c, d, F0, K0, 7, 6, x); - d, a = R(d, e, a, b, c, F0, K0, 9, 7, x); - c, e = R(c, d, e, a, b, F0, K0, 11, 8, x); - b, d = R(b, c, d, e, a, F0, K0, 13, 9, x); - a, c = R(a, b, c, d, e, F0, K0, 14, 10, x); - e, b = R(e, a, b, c, d, F0, K0, 15, 11, x); - d, a = R(d, e, a, b, c, F0, K0, 6, 12, x); - c, e = R(c, d, e, a, b, F0, K0, 7, 13, x); - b, d = R(b, c, d, e, a, F0, K0, 9, 14, x); - a, c = R(a, b, c, d, e, F0, K0, 8, 15, x); #/* #15 */ - #/* Round 2 */ - e, b = R(e, a, b, c, d, F1, K1, 7, 7, x); - d, a = R(d, e, a, b, c, F1, K1, 6, 4, x); - c, e = R(c, d, e, a, b, F1, K1, 8, 13, x); - b, d = R(b, c, d, e, a, F1, K1, 13, 1, x); - a, c = R(a, b, c, d, e, F1, K1, 11, 10, x); - e, b = R(e, a, b, c, d, F1, K1, 9, 6, x); - d, a = R(d, e, a, b, c, F1, K1, 7, 15, x); - c, e = R(c, d, e, a, b, F1, K1, 15, 3, x); - b, d = R(b, c, d, e, a, F1, K1, 7, 12, x); - a, c = R(a, b, c, d, e, F1, K1, 12, 0, x); - e, b = R(e, a, b, c, d, F1, K1, 15, 9, x); - d, a = R(d, e, a, b, c, F1, K1, 9, 5, x); - c, e = R(c, d, e, a, b, F1, K1, 11, 2, x); - b, d = R(b, c, d, e, a, F1, K1, 7, 14, x); - a, c = R(a, b, c, d, e, F1, K1, 13, 11, x); - e, b = R(e, a, b, c, d, F1, K1, 12, 8, x); #/* #31 */ - #/* Round 3 */ - d, a = R(d, e, a, b, c, F2, K2, 11, 3, x); - c, e = R(c, d, e, a, b, F2, K2, 13, 10, x); - b, d = R(b, c, d, e, a, F2, K2, 6, 14, x); - a, c = R(a, b, c, d, e, F2, K2, 7, 4, x); - e, b = R(e, a, b, c, d, F2, K2, 14, 9, x); - d, a = R(d, e, a, b, c, F2, K2, 9, 15, x); - c, e = R(c, d, e, a, b, F2, K2, 13, 8, x); - b, d = R(b, c, d, e, a, F2, K2, 15, 1, x); - a, c = R(a, b, c, d, e, F2, K2, 14, 2, x); - e, b = R(e, a, b, c, d, F2, K2, 8, 7, x); - d, a = R(d, e, a, b, c, F2, K2, 13, 0, x); - c, e = R(c, d, e, a, b, F2, K2, 6, 6, x); - b, d = R(b, c, d, e, a, F2, K2, 5, 13, x); - a, c = R(a, b, c, d, e, F2, K2, 12, 11, x); - e, b = R(e, a, b, c, d, F2, K2, 7, 5, x); - d, a = R(d, e, a, b, c, F2, K2, 5, 12, x); #/* #47 */ - #/* Round 4 */ - c, e = R(c, d, e, a, b, F3, K3, 11, 1, x); - b, d = R(b, c, d, e, a, F3, K3, 12, 9, x); - a, c = R(a, b, c, d, e, F3, K3, 14, 11, x); - e, b = R(e, a, b, c, d, F3, K3, 15, 10, x); - d, a = R(d, e, a, b, c, F3, K3, 14, 0, x); - c, e = R(c, d, e, a, b, F3, K3, 15, 8, x); - b, d = R(b, c, d, e, a, F3, K3, 9, 12, x); - a, c = R(a, b, c, d, e, F3, K3, 8, 4, x); - e, b = R(e, a, b, c, d, F3, K3, 9, 13, x); - d, a = R(d, e, a, b, c, F3, K3, 14, 3, x); - c, e = R(c, d, e, a, b, F3, K3, 5, 7, x); - b, d = R(b, c, d, e, a, F3, K3, 6, 15, x); - a, c = R(a, b, c, d, e, F3, K3, 8, 14, x); - e, b = R(e, a, b, c, d, F3, K3, 6, 5, x); - d, a = R(d, e, a, b, c, F3, K3, 5, 6, x); - c, e = R(c, d, e, a, b, F3, K3, 12, 2, x); #/* #63 */ - #/* Round 5 */ - b, d = R(b, c, d, e, a, F4, K4, 9, 4, x); - a, c = R(a, b, c, d, e, F4, K4, 15, 0, x); - e, b = R(e, a, b, c, d, F4, K4, 5, 5, x); - d, a = R(d, e, a, b, c, F4, K4, 11, 9, x); - c, e = R(c, d, e, a, b, F4, K4, 6, 7, x); - b, d = R(b, c, d, e, a, F4, K4, 8, 12, x); - a, c = R(a, b, c, d, e, F4, K4, 13, 2, x); - e, b = R(e, a, b, c, d, F4, K4, 12, 10, x); - d, a = R(d, e, a, b, c, F4, K4, 5, 14, x); - c, e = R(c, d, e, a, b, F4, K4, 12, 1, x); - b, d = R(b, c, d, e, a, F4, K4, 13, 3, x); - a, c = R(a, b, c, d, e, F4, K4, 14, 8, x); - e, b = R(e, a, b, c, d, F4, K4, 11, 11, x); - d, a = R(d, e, a, b, c, F4, K4, 8, 6, x); - c, e = R(c, d, e, a, b, F4, K4, 5, 15, x); - b, d = R(b, c, d, e, a, F4, K4, 6, 13, x); #/* #79 */ - - aa = a; - bb = b; - cc = c; - dd = d; - ee = e; - - a = state[0] - b = state[1] - c = state[2] - d = state[3] - e = state[4] - - #/* Parallel round 1 */ - a, c = R(a, b, c, d, e, F4, KK0, 8, 5, x) - e, b = R(e, a, b, c, d, F4, KK0, 9, 14, x) - d, a = R(d, e, a, b, c, F4, KK0, 9, 7, x) - c, e = R(c, d, e, a, b, F4, KK0, 11, 0, x) - b, d = R(b, c, d, e, a, F4, KK0, 13, 9, x) - a, c = R(a, b, c, d, e, F4, KK0, 15, 2, x) - e, b = R(e, a, b, c, d, F4, KK0, 15, 11, x) - d, a = R(d, e, a, b, c, F4, KK0, 5, 4, x) - c, e = R(c, d, e, a, b, F4, KK0, 7, 13, x) - b, d = R(b, c, d, e, a, F4, KK0, 7, 6, x) - a, c = R(a, b, c, d, e, F4, KK0, 8, 15, x) - e, b = R(e, a, b, c, d, F4, KK0, 11, 8, x) - d, a = R(d, e, a, b, c, F4, KK0, 14, 1, x) - c, e = R(c, d, e, a, b, F4, KK0, 14, 10, x) - b, d = R(b, c, d, e, a, F4, KK0, 12, 3, x) - a, c = R(a, b, c, d, e, F4, KK0, 6, 12, x) #/* #15 */ - #/* Parallel round 2 */ - e, b = R(e, a, b, c, d, F3, KK1, 9, 6, x) - d, a = R(d, e, a, b, c, F3, KK1, 13, 11, x) - c, e = R(c, d, e, a, b, F3, KK1, 15, 3, x) - b, d = R(b, c, d, e, a, F3, KK1, 7, 7, x) - a, c = R(a, b, c, d, e, F3, KK1, 12, 0, x) - e, b = R(e, a, b, c, d, F3, KK1, 8, 13, x) - d, a = R(d, e, a, b, c, F3, KK1, 9, 5, x) - c, e = R(c, d, e, a, b, F3, KK1, 11, 10, x) - b, d = R(b, c, d, e, a, F3, KK1, 7, 14, x) - a, c = R(a, b, c, d, e, F3, KK1, 7, 15, x) - e, b = R(e, a, b, c, d, F3, KK1, 12, 8, x) - d, a = R(d, e, a, b, c, F3, KK1, 7, 12, x) - c, e = R(c, d, e, a, b, F3, KK1, 6, 4, x) - b, d = R(b, c, d, e, a, F3, KK1, 15, 9, x) - a, c = R(a, b, c, d, e, F3, KK1, 13, 1, x) - e, b = R(e, a, b, c, d, F3, KK1, 11, 2, x) #/* #31 */ - #/* Parallel round 3 */ - d, a = R(d, e, a, b, c, F2, KK2, 9, 15, x) - c, e = R(c, d, e, a, b, F2, KK2, 7, 5, x) - b, d = R(b, c, d, e, a, F2, KK2, 15, 1, x) - a, c = R(a, b, c, d, e, F2, KK2, 11, 3, x) - e, b = R(e, a, b, c, d, F2, KK2, 8, 7, x) - d, a = R(d, e, a, b, c, F2, KK2, 6, 14, x) - c, e = R(c, d, e, a, b, F2, KK2, 6, 6, x) - b, d = R(b, c, d, e, a, F2, KK2, 14, 9, x) - a, c = R(a, b, c, d, e, F2, KK2, 12, 11, x) - e, b = R(e, a, b, c, d, F2, KK2, 13, 8, x) - d, a = R(d, e, a, b, c, F2, KK2, 5, 12, x) - c, e = R(c, d, e, a, b, F2, KK2, 14, 2, x) - b, d = R(b, c, d, e, a, F2, KK2, 13, 10, x) - a, c = R(a, b, c, d, e, F2, KK2, 13, 0, x) - e, b = R(e, a, b, c, d, F2, KK2, 7, 4, x) - d, a = R(d, e, a, b, c, F2, KK2, 5, 13, x) #/* #47 */ - #/* Parallel round 4 */ - c, e = R(c, d, e, a, b, F1, KK3, 15, 8, x) - b, d = R(b, c, d, e, a, F1, KK3, 5, 6, x) - a, c = R(a, b, c, d, e, F1, KK3, 8, 4, x) - e, b = R(e, a, b, c, d, F1, KK3, 11, 1, x) - d, a = R(d, e, a, b, c, F1, KK3, 14, 3, x) - c, e = R(c, d, e, a, b, F1, KK3, 14, 11, x) - b, d = R(b, c, d, e, a, F1, KK3, 6, 15, x) - a, c = R(a, b, c, d, e, F1, KK3, 14, 0, x) - e, b = R(e, a, b, c, d, F1, KK3, 6, 5, x) - d, a = R(d, e, a, b, c, F1, KK3, 9, 12, x) - c, e = R(c, d, e, a, b, F1, KK3, 12, 2, x) - b, d = R(b, c, d, e, a, F1, KK3, 9, 13, x) - a, c = R(a, b, c, d, e, F1, KK3, 12, 9, x) - e, b = R(e, a, b, c, d, F1, KK3, 5, 7, x) - d, a = R(d, e, a, b, c, F1, KK3, 15, 10, x) - c, e = R(c, d, e, a, b, F1, KK3, 8, 14, x) #/* #63 */ - #/* Parallel round 5 */ - b, d = R(b, c, d, e, a, F0, KK4, 8, 12, x) - a, c = R(a, b, c, d, e, F0, KK4, 5, 15, x) - e, b = R(e, a, b, c, d, F0, KK4, 12, 10, x) - d, a = R(d, e, a, b, c, F0, KK4, 9, 4, x) - c, e = R(c, d, e, a, b, F0, KK4, 12, 1, x) - b, d = R(b, c, d, e, a, F0, KK4, 5, 5, x) - a, c = R(a, b, c, d, e, F0, KK4, 14, 8, x) - e, b = R(e, a, b, c, d, F0, KK4, 6, 7, x) - d, a = R(d, e, a, b, c, F0, KK4, 8, 6, x) - c, e = R(c, d, e, a, b, F0, KK4, 13, 2, x) - b, d = R(b, c, d, e, a, F0, KK4, 6, 13, x) - a, c = R(a, b, c, d, e, F0, KK4, 5, 14, x) - e, b = R(e, a, b, c, d, F0, KK4, 15, 0, x) - d, a = R(d, e, a, b, c, F0, KK4, 13, 3, x) - c, e = R(c, d, e, a, b, F0, KK4, 11, 9, x) - b, d = R(b, c, d, e, a, F0, KK4, 11, 11, x) #/* #79 */ - - t = (state[1] + cc + d) % 0x100000000; - state[1] = (state[2] + dd + e) % 0x100000000; - state[2] = (state[3] + ee + a) % 0x100000000; - state[3] = (state[4] + aa + b) % 0x100000000; - state[4] = (state[0] + bb + c) % 0x100000000; - state[0] = t % 0x100000000; - - pass - - -def RMD160Update(ctx, inp, inplen): - if type(inp) == str: - inp = [ord(i)&0xff for i in inp] - - have = int((ctx.count // 8) % 64) - inplen = int(inplen) - need = 64 - have - ctx.count += 8 * inplen - off = 0 - if inplen >= need: - if have: - for i in range(need): - ctx.buffer[have+i] = inp[i] - RMD160Transform(ctx.state, ctx.buffer) - off = need - have = 0 - while off + 64 <= inplen: - RMD160Transform(ctx.state, inp[off:]) #<--- - off += 64 - if off < inplen: - # memcpy(ctx->buffer + have, input+off, len-off); - for i in range(inplen - off): - ctx.buffer[have+i] = inp[off+i] - -def RMD160Final(ctx): - size = struct.pack(" 73: return False - if (sig[0] != 0x30): return False - if (sig[1] != len(sig)-3): return False - rlen = sig[3] - if (5+rlen >= len(sig)): return False - slen = sig[5+rlen] - if (rlen + slen + 7 != len(sig)): return False - if (sig[2] != 0x02): return False - if (rlen == 0): return False - if (sig[4] & 0x80): return False - if (rlen > 1 and (sig[4] == 0x00) and not (sig[5] & 0x80)): return False - if (sig[4+rlen] != 0x02): return False - if (slen == 0): return False - if (sig[rlen+6] & 0x80): return False - if (slen > 1 and (sig[6+rlen] == 0x00) and not (sig[7+rlen] & 0x80)): - return False - return True - -def txhash(tx, hashcode=None): - if isinstance(tx, str) and re.match('^[0-9a-fA-F]*$', tx): - tx = changebase(tx, 16, 256) - if hashcode: - return dbl_sha256(from_string_to_bytes(tx) + encode(int(hashcode), 256, 4)[::-1]) - else: - return safe_hexlify(bin_dbl_sha256(tx)[::-1]) - - -def bin_txhash(tx, hashcode=None): - return binascii.unhexlify(txhash(tx, hashcode)) - - -def ecdsa_tx_sign(tx, priv, hashcode=SIGHASH_ALL): - rawsig = ecdsa_raw_sign(bin_txhash(tx, hashcode), priv) - return der_encode_sig(*rawsig)+encode(hashcode, 16, 2) - - -def ecdsa_tx_verify(tx, sig, pub, hashcode=SIGHASH_ALL): - return ecdsa_raw_verify(bin_txhash(tx, hashcode), der_decode_sig(sig), pub) - - -def ecdsa_tx_recover(tx, sig, hashcode=SIGHASH_ALL): - z = bin_txhash(tx, hashcode) - _, r, s = der_decode_sig(sig) - left = ecdsa_raw_recover(z, (0, r, s)) - right = ecdsa_raw_recover(z, (1, r, s)) - return (encode_pubkey(left, 'hex'), encode_pubkey(right, 'hex')) - -# Scripts - - -def mk_pubkey_script(addr): - # Keep the auxiliary functions around for altcoins' sake - return '76a914' + b58check_to_hex(addr) + '88ac' - - -def mk_scripthash_script(addr): - return 'a914' + b58check_to_hex(addr) + '87' - -# Address representation to output script - - -def address_to_script(addr): - if addr[0] == '3' or addr[0] == '2': - return mk_scripthash_script(addr) - else: - return mk_pubkey_script(addr) - -# Output script to address representation - - -def script_to_address(script, vbyte=0): - if re.match('^[0-9a-fA-F]*$', script): - script = binascii.unhexlify(script) - if script[:3] == b'\x76\xa9\x14' and script[-2:] == b'\x88\xac' and len(script) == 25: - return bin_to_b58check(script[3:-2], vbyte) # pubkey hash addresses - else: - if vbyte in [111, 196]: - # Testnet - scripthash_byte = 196 - elif vbyte == 0: - # Mainnet - scripthash_byte = 5 - else: - scripthash_byte = vbyte - # BIP0016 scripthash addresses - return bin_to_b58check(script[2:-1], scripthash_byte) - - -def p2sh_scriptaddr(script, magicbyte=5): - if re.match('^[0-9a-fA-F]*$', script): - script = binascii.unhexlify(script) - return hex_to_b58check(hash160(script), magicbyte) -scriptaddr = p2sh_scriptaddr - - -def deserialize_script(script): - if isinstance(script, str) and re.match('^[0-9a-fA-F]*$', script): - return json_changebase(deserialize_script(binascii.unhexlify(script)), - lambda x: safe_hexlify(x)) - out, pos = [], 0 - while pos < len(script): - code = from_byte_to_int(script[pos]) - if code == 0: - out.append(None) - pos += 1 - elif code <= 75: - out.append(script[pos+1:pos+1+code]) - pos += 1 + code - elif code <= 78: - szsz = pow(2, code - 76) - sz = decode(script[pos+szsz: pos:-1], 256) - out.append(script[pos + 1 + szsz:pos + 1 + szsz + sz]) - pos += 1 + szsz + sz - elif code <= 96: - out.append(code - 80) - pos += 1 - else: - out.append(code) - pos += 1 - return out - - -def serialize_script_unit(unit): - if isinstance(unit, int): - if unit < 16: - return from_int_to_byte(unit + 80) - else: - return from_int_to_byte(unit) - elif unit is None: - return b'\x00' - else: - if len(unit) <= 75: - return from_int_to_byte(len(unit))+unit - elif len(unit) < 256: - return from_int_to_byte(76)+from_int_to_byte(len(unit))+unit - elif len(unit) < 65536: - return from_int_to_byte(77)+encode(len(unit), 256, 2)[::-1]+unit - else: - return from_int_to_byte(78)+encode(len(unit), 256, 4)[::-1]+unit - - -if is_python2: - def serialize_script(script): - if json_is_base(script, 16): - return binascii.hexlify(serialize_script(json_changebase(script, - lambda x: binascii.unhexlify(x)))) - return ''.join(map(serialize_script_unit, script)) -else: - def serialize_script(script): - if json_is_base(script, 16): - return safe_hexlify(serialize_script(json_changebase(script, - lambda x: binascii.unhexlify(x)))) - - result = bytes() - for b in map(serialize_script_unit, script): - result += b if isinstance(b, bytes) else bytes(b, 'utf-8') - return result - - -def mk_multisig_script(*args): # [pubs],k or pub1,pub2...pub[n],k - if isinstance(args[0], list): - pubs, k = args[0], int(args[1]) - else: - pubs = list(filter(lambda x: len(str(x)) >= 32, args)) - k = int(args[len(pubs)]) - return serialize_script([k]+pubs+[len(pubs)]+[0xae]) - -# Signing and verifying - - -def verify_tx_input(tx, i, script, sig, pub): - if re.match('^[0-9a-fA-F]*$', tx): - tx = binascii.unhexlify(tx) - if re.match('^[0-9a-fA-F]*$', script): - script = binascii.unhexlify(script) - if not re.match('^[0-9a-fA-F]*$', sig): - sig = safe_hexlify(sig) - hashcode = decode(sig[-2:], 16) - modtx = signature_form(tx, int(i), script, hashcode) - return ecdsa_tx_verify(modtx, sig, pub, hashcode) - - -def sign(tx, i, priv, hashcode=SIGHASH_ALL): - i = int(i) - if (not is_python2 and isinstance(re, bytes)) or not re.match('^[0-9a-fA-F]*$', tx): - return binascii.unhexlify(sign(safe_hexlify(tx), i, priv)) - if len(priv) <= 33: - priv = safe_hexlify(priv) - pub = privkey_to_pubkey(priv) - address = pubkey_to_address(pub) - signing_tx = signature_form(tx, i, mk_pubkey_script(address), hashcode) - sig = ecdsa_tx_sign(signing_tx, priv, hashcode) - txobj = deserialize(tx) - txobj["ins"][i]["script"] = serialize_script([sig, pub]) - return serialize(txobj) - - -def signall(tx, priv): - # if priv is a dictionary, assume format is - # { 'txinhash:txinidx' : privkey } - if isinstance(priv, dict): - for e, i in enumerate(deserialize(tx)["ins"]): - k = priv["%s:%d" % (i["outpoint"]["hash"], i["outpoint"]["index"])] - tx = sign(tx, e, k) - else: - for i in range(len(deserialize(tx)["ins"])): - tx = sign(tx, i, priv) - return tx - - -def multisign(tx, i, script, pk, hashcode=SIGHASH_ALL): - if re.match('^[0-9a-fA-F]*$', tx): - tx = binascii.unhexlify(tx) - if re.match('^[0-9a-fA-F]*$', script): - script = binascii.unhexlify(script) - modtx = signature_form(tx, i, script, hashcode) - return ecdsa_tx_sign(modtx, pk, hashcode) - - -def apply_multisignatures(*args): - # tx,i,script,sigs OR tx,i,script,sig1,sig2...,sig[n] - tx, i, script = args[0], int(args[1]), args[2] - sigs = args[3] if isinstance(args[3], list) else list(args[3:]) - - if isinstance(script, str) and re.match('^[0-9a-fA-F]*$', script): - script = binascii.unhexlify(script) - sigs = [binascii.unhexlify(x) if x[:2] == '30' else x for x in sigs] - if isinstance(tx, str) and re.match('^[0-9a-fA-F]*$', tx): - return safe_hexlify(apply_multisignatures(binascii.unhexlify(tx), i, script, sigs)) - - # Not pushing empty elements on the top of the stack if passing no - # script (in case of bare multisig inputs there is no script) - script_blob = [] if script.__len__() == 0 else [script] - - txobj = deserialize(tx) - txobj["ins"][i]["script"] = serialize_script([None]+sigs+script_blob) - return serialize(txobj) - - -def is_inp(arg): - return len(arg) > 64 or "output" in arg or "outpoint" in arg - - -def mktx(*args): - # [in0, in1...],[out0, out1...] or in0, in1 ... out0 out1 ... - ins, outs = [], [] - for arg in args: - if isinstance(arg, list): - for a in arg: (ins if is_inp(a) else outs).append(a) - else: - (ins if is_inp(arg) else outs).append(arg) - - txobj = {"locktime": 0, "version": 1, "ins": [], "outs": []} - for i in ins: - if isinstance(i, dict) and "outpoint" in i: - txobj["ins"].append(i) - else: - if isinstance(i, dict) and "output" in i: - i = i["output"] - txobj["ins"].append({ - "outpoint": {"hash": i[:64], "index": int(i[65:])}, - "script": "", - "sequence": 4294967295 - }) - for o in outs: - if isinstance(o, string_or_bytes_types): - addr = o[:o.find(':')] - val = int(o[o.find(':')+1:]) - o = {} - if re.match('^[0-9a-fA-F]*$', addr): - o["script"] = addr - else: - o["address"] = addr - o["value"] = val - - outobj = {} - if "address" in o: - outobj["script"] = address_to_script(o["address"]) - elif "script" in o: - outobj["script"] = o["script"] - else: - raise Exception("Could not find 'address' or 'script' in output.") - outobj["value"] = o["value"] - txobj["outs"].append(outobj) - - return serialize(txobj) - - -def select(unspent, value): - value = int(value) - high = [u for u in unspent if u["value"] >= value] - high.sort(key=lambda u: u["value"]) - low = [u for u in unspent if u["value"] < value] - low.sort(key=lambda u: -u["value"]) - if len(high): - return [high[0]] - i, tv = 0, 0 - while tv < value and i < len(low): - tv += low[i]["value"] - i += 1 - if tv < value: - raise Exception("Not enough funds") - return low[:i] - -# Only takes inputs of the form { "output": blah, "value": foo } - - -def mksend(*args): - argz, change, fee = args[:-2], args[-2], int(args[-1]) - ins, outs = [], [] - for arg in argz: - if isinstance(arg, list): - for a in arg: - (ins if is_inp(a) else outs).append(a) - else: - (ins if is_inp(arg) else outs).append(arg) - - isum = sum([i["value"] for i in ins]) - osum, outputs2 = 0, [] - for o in outs: - if isinstance(o, string_types): - o2 = { - "address": o[:o.find(':')], - "value": int(o[o.find(':')+1:]) - } - else: - o2 = o - outputs2.append(o2) - osum += o2["value"] - - if isum < osum+fee: - raise Exception("Not enough money") - elif isum > osum+fee+5430: - outputs2 += [{"address": change, "value": isum-osum-fee}] - - return mktx(ins, outputs2) diff --git a/src/lib/pybitcointools/pybtctool b/src/lib/pybitcointools/pybtctool deleted file mode 100644 index 2f6b3dcc..00000000 --- a/src/lib/pybitcointools/pybtctool +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/python -import sys, json, re -from bitcoin import * - -if len(sys.argv) == 1: - print "pybtctool ..." -else: - cmdargs, preargs, kwargs = [], [], {} - i = 2 - # Process first arg tag - if sys.argv[1] == '-s': - preargs.extend(re.findall(r'\S\S*', sys.stdin.read())) - elif sys.argv[1] == '-B': - preargs.extend([sys.stdin.read()]) - elif sys.argv[1] == '-b': - preargs.extend([sys.stdin.read()[:-1]]) - elif sys.argv[1] == '-j': - preargs.extend([json.loads(sys.stdin.read())]) - elif sys.argv[1] == '-J': - preargs.extend(json.loads(sys.stdin.read())) - else: - i = 1 - while i < len(sys.argv): - if sys.argv[i][:2] == '--': - kwargs[sys.argv[i][2:]] = sys.argv[i+1] - i += 2 - else: - cmdargs.append(sys.argv[i]) - i += 1 - cmd = cmdargs[0] - args = preargs + cmdargs[1:] - o = vars()[cmd](*args, **kwargs) - if isinstance(o, (list, dict)): - print json.dumps(o) - else: - print o diff --git a/src/lib/pybitcointools/setup.py b/src/lib/pybitcointools/setup.py deleted file mode 100644 index e01a9bfc..00000000 --- a/src/lib/pybitcointools/setup.py +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env python -try: - from setuptools import setup -except ImportError: - from distutils.core import setup - -setup(name='bitcoin', - version='1.1.42', - description='Python Bitcoin Tools', - author='Vitalik Buterin', - author_email='vbuterin@gmail.com', - url='http://github.com/vbuterin/pybitcointools', - packages=['bitcoin'], - scripts=['pybtctool'], - include_package_data=True, - data_files=[("", ["LICENSE"]), ("bitcoin", ["bitcoin/english.txt"])], - ) diff --git a/src/lib/pybitcointools/test.py b/src/lib/pybitcointools/test.py deleted file mode 100644 index 8fb8bdc1..00000000 --- a/src/lib/pybitcointools/test.py +++ /dev/null @@ -1,496 +0,0 @@ -import json -import os -import random -import unittest - -import bitcoin.ripemd as ripemd -from bitcoin import * - - -class TestECCArithmetic(unittest.TestCase): - - @classmethod - def setUpClass(cls): - print('Starting ECC arithmetic tests') - - def test_all(self): - for i in range(8): - print('### Round %d' % (i+1)) - x, y = random.randrange(2**256), random.randrange(2**256) - self.assertEqual( - multiply(multiply(G, x), y)[0], - multiply(multiply(G, y), x)[0] - ) - self.assertEqual( - - add_pubkeys(multiply(G, x), multiply(G, y))[0], - multiply(G, add_privkeys(x, y))[0] - ) - - hx, hy = encode(x % N, 16, 64), encode(y % N, 16, 64) - self.assertEqual( - multiply(multiply(G, hx), hy)[0], - multiply(multiply(G, hy), hx)[0] - ) - self.assertEqual( - add_pubkeys(multiply(G, hx), multiply(G, hy))[0], - multiply(G, add_privkeys(hx, hy))[0] - ) - self.assertEqual( - b58check_to_hex(pubtoaddr(privtopub(x))), - b58check_to_hex(pubtoaddr(multiply(G, hx), 23)) - ) - - p = privtopub(sha256(str(x))) - if i % 2 == 1: - p = changebase(p, 16, 256) - self.assertEqual(p, decompress(compress(p))) - self.assertEqual(G[0], multiply(divide(G, x), x)[0]) - - -class TestBases(unittest.TestCase): - - @classmethod - def setUpClass(cls): - print('Starting base change tests') - - def test_all(self): - data = [ - [10, '65535', 16, 'ffff'], - [16, 'deadbeef', 10, '3735928559'], - [10, '0', 16, ''], - [256, b'34567', 10, '219919234615'], - [10, '444', 16, '1bc'], - [256, b'\x03\x04\x05\x06\x07', 10, '12952339975'], - [16, '3132333435', 256, b'12345'] - ] - for prebase, preval, postbase, postval in data: - self.assertEqual(changebase(preval, prebase, postbase), postval) - - for i in range(100): - x = random.randrange(1, 9999999999999999) - frm = random.choice([2, 10, 16, 58, 256]) - to = random.choice([2, 10, 16, 58, 256]) - self.assertEqual(decode(encode(x, to), to), x) - self.assertEqual(changebase(encode(x, frm), frm, to), encode(x, to)) - self.assertEqual(decode(changebase(encode(x, frm), frm, to), to), x) - - -class TestElectrumWalletInternalConsistency(unittest.TestCase): - - @classmethod - def setUpClass(cls): - print('Starting Electrum wallet internal consistency tests') - - def test_all(self): - for i in range(3): - seed = sha256(str(random.randrange(2**40)))[:32] - mpk = electrum_mpk(seed) - for i in range(5): - pk = electrum_privkey(seed, i) - pub = electrum_pubkey((mpk, seed)[i % 2], i) - pub2 = privtopub(pk) - self.assertEqual( - pub, - pub2, - 'Does not match! Details:\nseed: %s\nmpk: %s\npriv: %s\npub: %s\npub2: %s' % ( - seed, mpk, pk, pub, pub2 - ) - ) - - -class TestRawSignRecover(unittest.TestCase): - - @classmethod - def setUpClass(cls): - print("Basic signing and recovery tests") - - def test_all(self): - for i in range(20): - k = sha256(str(i)) - s = ecdsa_raw_sign('35' * 32, k) - self.assertEqual( - ecdsa_raw_recover('35' * 32, s), - decode_pubkey(privtopub(k)) - ) - - -class TestTransactionSignVerify(unittest.TestCase): - - @classmethod - def setUpClass(cls): - print("Transaction-style signing and verification tests") - - def test_all(self): - alphabet = "1234567890qwertyuiopasdfghjklzxcvbnm" - for i in range(10): - msg = ''.join([random.choice(alphabet) for i in range(random.randrange(20, 200))]) - priv = sha256(str(random.randrange(2**256))) - pub = privtopub(priv) - sig = ecdsa_tx_sign(msg, priv) - self.assertTrue( - ecdsa_tx_verify(msg, sig, pub), - "Verification error" - ) - - self.assertIn( - pub, - ecdsa_tx_recover(msg, sig), - "Recovery failed" - ) - - -class TestSerialize(unittest.TestCase): - - def test_serialize(self): - tx = '0100000001239f932c780e517015842f3b02ff765fba97f9f63f9f1bc718b686a56ed9c73400000000fd5d010047304402200c40fa58d3f6d5537a343cf9c8d13bc7470baf1d13867e0de3e535cd6b4354c802200f2b48f67494835b060d0b2ff85657d2ba2d9ea4e697888c8cb580e8658183a801483045022056f488c59849a4259e7cef70fe5d6d53a4bd1c59a195b0577bd81cb76044beca022100a735b319fa66af7b178fc719b93f905961ef4d4446deca8757a90de2106dd98a014cc95241046c7d87fd72caeab48e937f2feca9e9a4bd77f0eff4ebb2dbbb9855c023e334e188d32aaec4632ea4cbc575c037d8101aec73d029236e7b1c2380f3e4ad7edced41046fd41cddf3bbda33a240b417a825cc46555949917c7ccf64c59f42fd8dfe95f34fae3b09ed279c8c5b3530510e8cca6230791102eef9961d895e8db54af0563c410488d618b988efd2511fc1f9c03f11c210808852b07fe46128c1a6b1155aa22cdf4b6802460ba593db2d11c7e6cbe19cedef76b7bcabd05d26fd97f4c5a59b225053aeffffffff0310270000000000001976a914a89733100315c37d228a529853af341a9d290a4588ac409c00000000000017a9142b56f9a4009d9ff99b8f97bea4455cd71135f5dd87409c00000000000017a9142b56f9a4009d9ff99b8f97bea4455cd71135f5dd8700000000' - self.assertEqual( - serialize(deserialize(tx)), - tx, - "Serialize roundtrip failed" - ) - - def test_serialize_script(self): - script = '47304402200c40fa58d3f6d5537a343cf9c8d13bc7470baf1d13867e0de3e535cd6b4354c802200f2b48f67494835b060d0b2ff85657d2ba2d9ea4e697888c8cb580e8658183a801483045022056f488c59849a4259e7cef70fe5d6d53a4bd1c59a195b0577bd81cb76044beca022100a735b319fa66af7b178fc719b93f905961ef4d4446deca8757a90de2106dd98a014cc95241046c7d87fd72caeab48e937f2feca9e9a4bd77f0eff4ebb2dbbb9855c023e334e188d32aaec4632ea4cbc575c037d8101aec73d029236e7b1c2380f3e4ad7edced41046fd41cddf3bbda33a240b417a825cc46555949917c7ccf64c59f42fd8dfe95f34fae3b09ed279c8c5b3530510e8cca6230791102eef9961d895e8db54af0563c410488d618b988efd2511fc1f9c03f11c210808852b07fe46128c1a6b1155aa22cdf4b6802460ba593db2d11c7e6cbe19cedef76b7bcabd05d26fd97f4c5a59b225053ae' - self.assertEqual( - serialize_script(deserialize_script(script)), - script, - "Script serialize roundtrip failed" - ) - - -class TestTransaction(unittest.TestCase): - @classmethod - def setUpClass(cls): - print("Attempting transaction creation") - - # FIXME: I don't know how to write this as a unit test. - # What should be asserted? - def test_all(self): - privs = [sha256(str(random.randrange(2**256))) for x in range(4)] - pubs = [privtopub(priv) for priv in privs] - addresses = [pubtoaddr(pub) for pub in pubs] - mscript = mk_multisig_script(pubs[1:], 2, 3) - msigaddr = p2sh_scriptaddr(mscript) - tx = mktx(['01'*32+':1', '23'*32+':2'], [msigaddr+':20202', addresses[0]+':40404']) - tx1 = sign(tx, 1, privs[0]) - - sig1 = multisign(tx, 0, mscript, privs[1]) - self.assertTrue(verify_tx_input(tx1, 0, mscript, sig1, pubs[1]), "Verification Error") - - sig3 = multisign(tx, 0, mscript, privs[3]) - self.assertTrue(verify_tx_input(tx1, 0, mscript, sig3, pubs[3]), "Verification Error") - - tx2 = apply_multisignatures(tx1, 0, mscript, [sig1, sig3]) - print("Outputting transaction: ", tx2) - - # https://github.com/vbuterin/pybitcointools/issues/71 - def test_multisig(self): - script = mk_multisig_script(["0254236f7d1124fc07600ad3eec5ac47393bf963fbf0608bcce255e685580d16d9", - "03560cad89031c412ad8619398bd43b3d673cb5bdcdac1afc46449382c6a8e0b2b"], - 2) - - self.assertEqual(p2sh_scriptaddr(script), "33byJBaS5N45RHFcatTSt9ZjiGb6nK4iV3") - - self.assertEqual(p2sh_scriptaddr(script, 0x05), "33byJBaS5N45RHFcatTSt9ZjiGb6nK4iV3") - self.assertEqual(p2sh_scriptaddr(script, 5), "33byJBaS5N45RHFcatTSt9ZjiGb6nK4iV3") - - self.assertEqual(p2sh_scriptaddr(script, 0xc4), "2MuABMvWTgpZRd4tAG25KW6YzvcoGVZDZYP") - self.assertEqual(p2sh_scriptaddr(script, 196), "2MuABMvWTgpZRd4tAG25KW6YzvcoGVZDZYP") - - -class TestDeterministicGenerate(unittest.TestCase): - @classmethod - def setUpClass(cls): - print("Beginning RFC6979 deterministic signing tests") - - def test_all(self): - # Created with python-ecdsa 0.9 - # Code to make your own vectors: - # class gen: - # def order(self): return 115792089237316195423570985008687907852837564279074904382605163141518161494337 - # dummy = gen() - # for i in range(10): ecdsa.rfc6979.generate_k(dummy, i, hashlib.sha256, hashlib.sha256(str(i)).digest()) - test_vectors = [ - 32783320859482229023646250050688645858316445811207841524283044428614360139869, - 109592113955144883013243055602231029997040992035200230706187150761552110229971, - 65765393578006003630736298397268097590176526363988568884298609868706232621488, - 85563144787585457107933685459469453513056530050186673491900346620874099325918, - 99829559501561741463404068005537785834525504175465914981205926165214632019533, - 7755945018790142325513649272940177083855222863968691658328003977498047013576, - 81516639518483202269820502976089105897400159721845694286620077204726637043798, - 52824159213002398817852821148973968315579759063230697131029801896913602807019, - 44033460667645047622273556650595158811264350043302911918907282441675680538675, - 32396602643737403620316035551493791485834117358805817054817536312402837398361 - ] - - for i, ti in enumerate(test_vectors): - mine = deterministic_generate_k(bin_sha256(str(i)), encode(i, 256, 32)) - self.assertEqual( - ti, - mine, - "Test vector does not match. Details:\n%s\n%s" % ( - ti, - mine - ) - ) - - -class TestBIP0032(unittest.TestCase): - """See: https://en.bitcoin.it/wiki/BIP_0032""" - @classmethod - def setUpClass(cls): - print("Beginning BIP0032 tests") - - def _full_derive(self, key, chain): - if len(chain) == 0: - return key - elif chain[0] == 'pub': - return self._full_derive(bip32_privtopub(key), chain[1:]) - else: - return self._full_derive(bip32_ckd(key, chain[0]), chain[1:]) - - def test_all(self): - test_vectors = [ - [[], 'xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi'], - [['pub'], 'xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8'], - [[2**31], 'xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7'], - [[2**31, 1], 'xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs'], - [[2**31, 1, 2**31 + 2], 'xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM'], - [[2**31, 1, 2**31 + 2, 'pub', 2, 1000000000], 'xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy'] - ] - - mk = bip32_master_key(safe_from_hex('000102030405060708090a0b0c0d0e0f')) - - for tv in test_vectors: - left, right = self._full_derive(mk, tv[0]), tv[1] - self.assertEqual( - left, - right, - r"Test vector does not match. Details: \n%s\n%s\n\%s" % ( - tv[0], - [x.encode('hex') if isinstance(x, str) else x for x in bip32_deserialize(left)], - [x.encode('hex') if isinstance(x, str) else x for x in bip32_deserialize(right)], - ) - ) - - def test_all_testnet(self): - test_vectors = [ - [[], 'tprv8ZgxMBicQKsPeDgjzdC36fs6bMjGApWDNLR9erAXMs5skhMv36j9MV5ecvfavji5khqjWaWSFhN3YcCUUdiKH6isR4Pwy3U5y5egddBr16m'], - [['pub'], 'tpubD6NzVbkrYhZ4XgiXtGrdW5XDAPFCL9h7we1vwNCpn8tGbBcgfVYjXyhWo4E1xkh56hjod1RhGjxbaTLV3X4FyWuejifB9jusQ46QzG87VKp'], - [[2**31], 'tprv8bxNLu25VazNnppTCP4fyhyCvBHcYtzE3wr3cwYeL4HA7yf6TLGEUdS4QC1vLT63TkjRssqJe4CvGNEC8DzW5AoPUw56D1Ayg6HY4oy8QZ9'], - [[2**31, 1], 'tprv8e8VYgZxtHsSdGrtvdxYaSrryZGiYviWzGWtDDKTGh5NMXAEB8gYSCLHpFCywNs5uqV7ghRjimALQJkRFZnUrLHpzi2pGkwqLtbubgWuQ8q'], - [[2**31, 1, 2**31 + 2], 'tprv8gjmbDPpbAirVSezBEMuwSu1Ci9EpUJWKokZTYccSZSomNMLytWyLdtDNHRbucNaRJWWHANf9AzEdWVAqahfyRjVMKbNRhBmxAM8EJr7R15'], - [[2**31, 1, 2**31 + 2, 'pub', 2, 1000000000], 'tpubDHNy3kAG39ThyiwwsgoKY4iRenXDRtce8qdCFJZXPMCJg5dsCUHayp84raLTpvyiNA9sXPob5rgqkKvkN8S7MMyXbnEhGJMW64Cf4vFAoaF'] - ] - - mk = bip32_master_key(safe_from_hex('000102030405060708090a0b0c0d0e0f'), TESTNET_PRIVATE) - - for tv in test_vectors: - left, right = self._full_derive(mk, tv[0]), tv[1] - self.assertEqual( - left, - right, - r"Test vector does not match. Details:\n%s\n%s\n%s\n\%s" % ( - left, - tv[0], - [x.encode('hex') if isinstance(x, str) else x for x in bip32_deserialize(left)], - [x.encode('hex') if isinstance(x, str) else x for x in bip32_deserialize(right)], - ) - ) - - def test_extra(self): - master = bip32_master_key(safe_from_hex("000102030405060708090a0b0c0d0e0f")) - - # m/0 - assert bip32_ckd(master, "0") == "xprv9uHRZZhbkedL37eZEnyrNsQPFZYRAvjy5rt6M1nbEkLSo378x1CQQLo2xxBvREwiK6kqf7GRNvsNEchwibzXaV6i5GcsgyjBeRguXhKsi4R" - assert bip32_privtopub(bip32_ckd(master, "0")) == "xpub68Gmy5EVb2BdFbj2LpWrk1M7obNuaPTpT5oh9QCCo5sRfqSHVYWex97WpDZzszdzHzxXDAzPLVSwybe4uPYkSk4G3gnrPqqkV9RyNzAcNJ1" - - # m/1 - assert bip32_ckd(master, "1") == "xprv9uHRZZhbkedL4yTpidDvuVfrdUkTbhDHviERRBkbzbNDZeMjWzqzKAdxWhzftGDSxDmBdakjqHiZJbkwiaTEXJdjZAaAjMZEE3PMbMrPJih" - assert bip32_privtopub(bip32_ckd(master, "1")) == "xpub68Gmy5EVb2BdHTYHpekwGdcbBWax19w9HwA2DaADYvuCSSgt4YAErxxSN1KWSnmyqkwRNbnTj3XiUBKmHeC8rTjLRPjSULcDKQQgfgJDppq" - - # m/0/0 - assert bip32_ckd(bip32_ckd(master, "0"), "0") == "xprv9ww7sMFLzJMzur2oEQDB642fbsMS4q6JRraMVTrM9bTWBq7NDS8ZpmsKVB4YF3mZecqax1fjnsPF19xnsJNfRp4RSyexacULXMKowSACTRc" - assert bip32_privtopub(bip32_ckd(bip32_ckd(master, "0"), "0")) == "xpub6AvUGrnEpfvJ8L7GLRkBTByQ9uBvUHp9o5VxHrFxhvzV4dSWkySpNaBoLR9FpbnwRmTa69yLHF3QfcaxbWT7gWdwws5k4dpmJvqpEuMWwnj" - - # m/0' - assert bip32_ckd(master, 2**31) == "xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7" - assert bip32_privtopub(bip32_ckd(master, 2**31)) == "xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw" - - # m/1' - assert bip32_ckd(master, 2**31 + 1) == "xprv9uHRZZhk6KAJFszJGW6LoUFq92uL7FvkBhmYiMurCWPHLJZkX2aGvNdRUBNnJu7nv36WnwCN59uNy6sxLDZvvNSgFz3TCCcKo7iutQzpg78" - assert bip32_privtopub(bip32_ckd(master, 2**31 + 1)) == "xpub68Gmy5EdvgibUN4mNXdMAcCZh4jpWiebYvh9WkKTkqvGD6tu4ZtXUAwuKSyF5DFZVmotf9UHFTGqSXo9qyDBSn47RkaN6Aedt9JbL7zcgSL" - - # m/1' - assert bip32_ckd(master, 1 + 2**31) == "xprv9uHRZZhk6KAJFszJGW6LoUFq92uL7FvkBhmYiMurCWPHLJZkX2aGvNdRUBNnJu7nv36WnwCN59uNy6sxLDZvvNSgFz3TCCcKo7iutQzpg78" - assert bip32_privtopub(bip32_ckd(master, 1 + 2**31)) == "xpub68Gmy5EdvgibUN4mNXdMAcCZh4jpWiebYvh9WkKTkqvGD6tu4ZtXUAwuKSyF5DFZVmotf9UHFTGqSXo9qyDBSn47RkaN6Aedt9JbL7zcgSL" - - # m/0'/0 - assert bip32_ckd(bip32_ckd(master, 2**31), "0") == "xprv9wTYmMFdV23N21MM6dLNavSQV7Sj7meSPXx6AV5eTdqqGLjycVjb115Ec5LgRAXscPZgy5G4jQ9csyyZLN3PZLxoM1h3BoPuEJzsgeypdKj" - assert bip32_privtopub(bip32_ckd(bip32_ckd(master, 2**31), "0")) == "xpub6ASuArnXKPbfEVRpCesNx4P939HDXENHkksgxsVG1yNp9958A33qYoPiTN9QrJmWFa2jNLdK84bWmyqTSPGtApP8P7nHUYwxHPhqmzUyeFG" - - # m/0'/0' - assert bip32_ckd(bip32_ckd(master, 2**31), 2**31) == "xprv9wTYmMFmpgaLB5Hge4YtaGqCKpsYPTD9vXWSsmdZrNU3Y2i4WoBykm6ZteeCLCCZpGxdHQuqEhM6Gdo2X6CVrQiTw6AAneF9WSkA9ewaxtS" - assert bip32_privtopub(bip32_ckd(bip32_ckd(master, 2**31), 2**31)) == "xpub6ASuArnff48dPZN9k65twQmvsri2nuw1HkS3gA3BQi12Qq3D4LWEJZR3jwCAr1NhsFMcQcBkmevmub6SLP37bNq91SEShXtEGUbX3GhNaGk" - - # m/44'/0'/0'/0/0 - assert bip32_ckd(bip32_ckd(bip32_ckd(bip32_ckd(bip32_ckd(master, 44 + 2**31), 2**31), 2**31), 0), 0) == "xprvA4A9CuBXhdBtCaLxwrw64Jaran4n1rgzeS5mjH47Ds8V67uZS8tTkG8jV3BZi83QqYXPcN4v8EjK2Aof4YcEeqLt688mV57gF4j6QZWdP9U" - assert bip32_privtopub(bip32_ckd(bip32_ckd(bip32_ckd(bip32_ckd(bip32_ckd(master, 44 + 2**31), 2**31), 2**31), 0), 0)) == "xpub6H9VcQiRXzkBR4RS3tU6RSXb8ouGRKQr1f1NXfTinCfTxvEhygCiJ4TDLHz1dyQ6d2Vz8Ne7eezkrViwaPo2ZMsNjVtFwvzsQXCDV6HJ3cV" - - -class TestStartingAddressAndScriptGenerationConsistency(unittest.TestCase): - @classmethod - def setUpClass(cls): - print("Starting address and script generation consistency tests") - - def test_all(self): - for i in range(5): - a = privtoaddr(random_key()) - self.assertEqual(a, script_to_address(address_to_script(a))) - self.assertEqual(a, script_to_address(address_to_script(a), 0)) - self.assertEqual(a, script_to_address(address_to_script(a), 0x00)) - - b = privtoaddr(random_key(), 5) - self.assertEqual(b, script_to_address(address_to_script(b))) - self.assertEqual(b, script_to_address(address_to_script(b), 0)) - self.assertEqual(b, script_to_address(address_to_script(b), 0x00)) - self.assertEqual(b, script_to_address(address_to_script(b), 5)) - self.assertEqual(b, script_to_address(address_to_script(b), 0x05)) - - - for i in range(5): - a = privtoaddr(random_key(), 0x6f) - self.assertEqual(a, script_to_address(address_to_script(a), 111)) - self.assertEqual(a, script_to_address(address_to_script(a), 0x6f)) - - b = privtoaddr(random_key(), 0xc4) - self.assertEqual(b, script_to_address(address_to_script(b), 111)) - self.assertEqual(b, script_to_address(address_to_script(b), 0x6f)) - self.assertEqual(b, script_to_address(address_to_script(b), 196)) - self.assertEqual(b, script_to_address(address_to_script(b), 0xc4)) - - -class TestRipeMD160PythonBackup(unittest.TestCase): - - @classmethod - def setUpClass(cls): - print('Testing the pure python backup for ripemd160') - - def test_all(self): - strvec = [ - '', - 'The quick brown fox jumps over the lazy dog', - 'The quick brown fox jumps over the lazy cog', - 'Nobody inspects the spammish repetition' - ] - - target = [ - '9c1185a5c5e9fc54612808977ee8f548b2258d31', - '37f332f68db77bd9d7edd4969571ad671cf9dd3b', - '132072df690933835eb8b6ad0b77e7b6f14acad7', - 'cc4a5ce1b3df48aec5d22d1f16b894a0b894eccc' - ] - - hash160target = [ - 'b472a266d0bd89c13706a4132ccfb16f7c3b9fcb', - '0e3397b4abc7a382b3ea2365883c3c7ca5f07600', - '53e0dacac5249e46114f65cb1f30d156b14e0bdc', - '1c9b7b48049a8f98699bca22a5856c5ef571cd68' - ] - - for i, s in enumerate(strvec): - digest = ripemd.RIPEMD160(s).digest() - hash160digest = ripemd.RIPEMD160(bin_sha256(s)).digest() - self.assertEqual(bytes_to_hex_string(digest), target[i]) - self.assertEqual(bytes_to_hex_string(hash160digest), hash160target[i]) - self.assertEqual(bytes_to_hex_string(bin_hash160(from_string_to_bytes(s))), hash160target[i]) - self.assertEqual(hash160(from_string_to_bytes(s)), hash160target[i]) - - -class TestScriptVsAddressOutputs(unittest.TestCase): - - @classmethod - def setUpClass(cls): - print('Testing script vs address outputs') - - def test_all(self): - addr0 = '1Lqgj1ThNfwLgHMp5qJUerYsuUEm8vHmVG' - script0 = '76a914d99f84267d1f90f3e870a5e9d2399918140be61d88ac' - addr1 = '31oSGBBNrpCiENH3XMZpiP6GTC4tad4bMy' - script1 = 'a9140136d001619faba572df2ef3d193a57ad29122d987' - - inputs = [{ - 'output': 'cd6219ea108119dc62fce09698b649efde56eca7ce223a3315e8b431f6280ce7:0', - 'value': 158000 - }] - - outputs = [ - [{'address': addr0, 'value': 1000}, {'address': addr1, 'value': 2000}], - [{'script': script0, 'value': 1000}, {'address': addr1, 'value': 2000}], - [{'address': addr0, 'value': 1000}, {'script': script1, 'value': 2000}], - [{'script': script0, 'value': 1000}, {'script': script1, 'value': 2000}], - [addr0 + ':1000', addr1 + ':2000'], - [script0 + ':1000', addr1 + ':2000'], - [addr0 + ':1000', script1 + ':2000'], - [script0 + ':1000', script1 + ':2000'] - ] - - for outs in outputs: - tx_struct = deserialize(mktx(inputs, outs)) - self.assertEqual(tx_struct['outs'], outputs[3]) - - -class TestConversions(unittest.TestCase): - @classmethod - def setUpClass(cls): - cls.privkey_hex = ( - "e9873d79c6d87dc0fb6a5778633389f4453213303da61f20bd67fc233aa33262" - ) - cls.privkey_bin = ( - b"\xe9\x87=y\xc6\xd8}\xc0\xfbjWxc3\x89\xf4E2\x130=\xa6\x1f \xbdg\xfc#:\xa32b" - ) - - cls.pubkey_hex = ( - "04588d202afcc1ee4ab5254c7847ec25b9a135bbda0f2bc69ee1a714749fd77dc9f88ff2a00d7e752d44cbe16e1ebcf0890b76ec7c78886109dee76ccfc8445424" - ) - cls.pubkey_bin = ( - b"\x04X\x8d *\xfc\xc1\xeeJ\xb5%LxG\xec%\xb9\xa15\xbb\xda\x0f+\xc6\x9e\xe1\xa7\x14t\x9f\xd7}\xc9\xf8\x8f\xf2\xa0\r~u-D\xcb\xe1n\x1e\xbc\xf0\x89\x0bv\xec|x\x88a\t\xde\xe7l\xcf\xc8DT$" - ) - - def test_privkey_to_pubkey(self): - pubkey_hex = privkey_to_pubkey(self.privkey_hex) - self.assertEqual(pubkey_hex, self.pubkey_hex) - - def test_changebase(self): - self.assertEqual( - self.pubkey_bin, - changebase( - self.pubkey_hex, 16, 256, minlen=len(self.pubkey_bin) - ) - ) - - self.assertEqual( - self.pubkey_hex, - changebase( - self.pubkey_bin, 256, 16, minlen=len(self.pubkey_hex) - ) - ) - - self.assertEqual( - self.privkey_bin, - changebase( - self.privkey_hex, 16, 256, minlen=len(self.privkey_bin) - ) - ) - - self.assertEqual( - self.privkey_hex, - changebase( - self.privkey_bin, 256, 16, minlen=len(self.privkey_hex) - ) - ) - - -if __name__ == '__main__': - unittest.main() diff --git a/src/lib/pybitcointools/test_stealth.py b/src/lib/pybitcointools/test_stealth.py deleted file mode 100644 index 01a1432d..00000000 --- a/src/lib/pybitcointools/test_stealth.py +++ /dev/null @@ -1,92 +0,0 @@ -import bitcoin as bc -import sys -import unittest - -class TestStealth(unittest.TestCase): - - def setUp(self): - - if sys.getrecursionlimit() < 1000: - sys.setrecursionlimit(1000) - - self.addr = 'vJmtjxSDxNPXL4RNapp9ARdqKz3uJyf1EDGjr1Fgqs9c8mYsVH82h8wvnA4i5rtJ57mr3kor1EVJrd4e5upACJd588xe52yXtzumxj' - self.scan_pub = '025e58a31122b38c86abc119b9379fe247410aee87a533f9c07b189aef6c3c1f52' - self.scan_priv = '3e49e7257cb31db997edb1cf8299af0f37e2663e2260e4b8033e49d39a6d02f2' - self.spend_pub = '03616562c98e7d7b74be409a787cec3a912122f3fb331a9bee9b0b73ce7b9f50af' - self.spend_priv = 'aa3db0cfb3edc94de4d10f873f8190843f2a17484f6021a95a7742302c744748' - self.ephem_pub = '03403d306ec35238384c7e340393335f9bc9bb4a2e574eb4e419452c4ea19f14b0' - self.ephem_priv = '9e63abaf8dcd5ea3919e6de0b6c544e00bf51bf92496113a01d6e369944dc091' - self.shared_secret = 'a4047ee231f4121e3a99a3a3378542e34a384b865a9917789920e1f13ffd91c6' - self.pay_pub = '02726112ad39cb6bf848b1b1ef30b88e35286bf99f746c2be575f96c0e02a9357c' - self.pay_priv = '4e422fb1e5e1db6c1f6ab32a7706d368ceb385e7fab098e633c5c5949c3b97cd' - - self.testnet_addr = 'waPUuLLykSnY3itzf1AyrQZm42F7KyB7SR5zpfqmnzPXWhx9kXLzV3EcyqzDdpTwngiyCCMUqztS9S1d7XJs3JMt3MsHPDpBCudvx9' - - def test_address_encoding(self): - - sc_pub, sp_pub = bc.basic_stealth_address_to_pubkeys(self.addr) - self.assertEqual(sc_pub, self.scan_pub) - self.assertEqual(sp_pub, self.spend_pub) - - stealth_addr2 = bc.pubkeys_to_basic_stealth_address(sc_pub, sp_pub) - self.assertEqual(stealth_addr2, self.addr) - - magic_byte_testnet = 43 - sc_pub, sp_pub = bc.basic_stealth_address_to_pubkeys(self.testnet_addr) - self.assertEqual(sc_pub, self.scan_pub) - self.assertEqual(sp_pub, self.spend_pub) - - stealth_addr2 = bc.pubkeys_to_basic_stealth_address(sc_pub, sp_pub, magic_byte_testnet) - self.assertEqual(stealth_addr2, self.testnet_addr) - - def test_shared_secret(self): - - sh_sec = bc.shared_secret_sender(self.scan_pub, self.ephem_priv) - self.assertEqual(sh_sec, self.shared_secret) - - sh_sec2 = bc.shared_secret_receiver(self.ephem_pub, self.scan_priv) - self.assertEqual(sh_sec2, self.shared_secret) - - def test_uncover_pay_keys(self): - - pub = bc.uncover_pay_pubkey_sender(self.scan_pub, self.spend_pub, self.ephem_priv) - pub2 = bc.uncover_pay_pubkey_receiver(self.scan_priv, self.spend_pub, self.ephem_pub) - self.assertEqual(pub, self.pay_pub) - self.assertEqual(pub2, self.pay_pub) - - priv = bc.uncover_pay_privkey(self.scan_priv, self.spend_priv, self.ephem_pub) - self.assertEqual(priv, self.pay_priv) - - def test_stealth_metadata_script(self): - - nonce = int('deadbeef', 16) - script = bc.mk_stealth_metadata_script(self.ephem_pub, nonce) - self.assertEqual(script[6:], 'deadbeef' + self.ephem_pub) - - eph_pub = bc.ephem_pubkey_from_tx_script(script) - self.assertEqual(eph_pub, self.ephem_pub) - - def test_stealth_tx_outputs(self): - - nonce = int('deadbeef', 16) - value = 10**8 - outputs = bc.mk_stealth_tx_outputs(self.addr, value, self.ephem_priv, nonce) - - self.assertEqual(outputs[0]['value'], 0) - self.assertEqual(outputs[0]['script'], '6a2606deadbeef' + self.ephem_pub) - self.assertEqual(outputs[1]['address'], bc.pubkey_to_address(self.pay_pub)) - self.assertEqual(outputs[1]['value'], value) - - outputs = bc.mk_stealth_tx_outputs(self.testnet_addr, value, self.ephem_priv, nonce, 'testnet') - - self.assertEqual(outputs[0]['value'], 0) - self.assertEqual(outputs[0]['script'], '6a2606deadbeef' + self.ephem_pub) - self.assertEqual(outputs[1]['address'], bc.pubkey_to_address(self.pay_pub, 111)) - self.assertEqual(outputs[1]['value'], value) - - self.assertRaises(Exception, bc.mk_stealth_tx_outputs, self.testnet_addr, value, self.ephem_priv, nonce, 'btc') - - self.assertRaises(Exception, bc.mk_stealth_tx_outputs, self.addr, value, self.ephem_priv, nonce, 'testnet') - -if __name__ == '__main__': - unittest.main() diff --git a/src/lib/pyelliptic/LICENSE b/src/lib/pyelliptic/LICENSE deleted file mode 100644 index 94a9ed02..00000000 --- a/src/lib/pyelliptic/LICENSE +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/src/lib/pyelliptic/README.md b/src/lib/pyelliptic/README.md deleted file mode 100644 index 587b1445..00000000 --- a/src/lib/pyelliptic/README.md +++ /dev/null @@ -1,67 +0,0 @@ -# PyElliptic - -PyElliptic is a high level wrapper for the cryptographic library : OpenSSL. -Under the GNU General Public License - -Python3 compatible. For GNU/Linux and Windows. -Require OpenSSL - -## Features - -### Asymmetric cryptography using Elliptic Curve Cryptography (ECC) - -* Key agreement : ECDH -* Digital signatures : ECDSA -* Hybrid encryption : ECIES (like RSA) - -### Symmetric cryptography - -* AES-128 (CBC, OFB, CFB) -* AES-256 (CBC, OFB, CFB) -* Blowfish (CFB and CBC) -* RC4 - -### Other - -* CSPRNG -* HMAC (using SHA512) -* PBKDF2 (SHA256 and SHA512) - -## Example - -```python -#!/usr/bin/python - -import pyelliptic - -# Symmetric encryption -iv = pyelliptic.Cipher.gen_IV('aes-256-cfb') -ctx = pyelliptic.Cipher("secretkey", iv, 1, ciphername='aes-256-cfb') - -ciphertext = ctx.update('test1') -ciphertext += ctx.update('test2') -ciphertext += ctx.final() - -ctx2 = pyelliptic.Cipher("secretkey", iv, 0, ciphername='aes-256-cfb') -print ctx2.ciphering(ciphertext) - -# Asymmetric encryption -alice = pyelliptic.ECC() # default curve: sect283r1 -bob = pyelliptic.ECC(curve='sect571r1') - -ciphertext = alice.encrypt("Hello Bob", bob.get_pubkey()) -print bob.decrypt(ciphertext) - -signature = bob.sign("Hello Alice") -# alice's job : -print pyelliptic.ECC(pubkey=bob.get_pubkey()).verify(signature, "Hello Alice") - -# ERROR !!! -try: - key = alice.get_ecdh_key(bob.get_pubkey()) -except: print("For ECDH key agreement, the keys must be defined on the same curve !") - -alice = pyelliptic.ECC(curve='sect571r1') -print alice.get_ecdh_key(bob.get_pubkey()).encode('hex') -print bob.get_ecdh_key(alice.get_pubkey()).encode('hex') -``` diff --git a/src/lib/pyelliptic/__init__.py b/src/lib/pyelliptic/__init__.py deleted file mode 100644 index 761d08af..00000000 --- a/src/lib/pyelliptic/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright (C) 2010 -# Author: Yann GUIBET -# Contact: - -__version__ = '1.3' - -__all__ = [ - 'OpenSSL', - 'ECC', - 'Cipher', - 'hmac_sha256', - 'hmac_sha512', - 'pbkdf2' -] - -from .openssl import OpenSSL -from .ecc import ECC -from .cipher import Cipher -from .hash import hmac_sha256, hmac_sha512, pbkdf2 diff --git a/src/lib/pyelliptic/arithmetic.py b/src/lib/pyelliptic/arithmetic.py deleted file mode 100644 index 1eec381a..00000000 --- a/src/lib/pyelliptic/arithmetic.py +++ /dev/null @@ -1,106 +0,0 @@ -import hashlib, re - -P = 2**256-2**32-2**9-2**8-2**7-2**6-2**4-1 -A = 0 -Gx = 55066263022277343669578718895168534326250603453777594175500187360389116729240 -Gy = 32670510020758816978083085130507043184471273380659243275938904335757337482424 -G = (Gx,Gy) - -def inv(a,n): - lm, hm = 1,0 - low, high = a%n,n - while low > 1: - r = high/low - nm, new = hm-lm*r, high-low*r - lm, low, hm, high = nm, new, lm, low - return lm % n - -def get_code_string(base): - if base == 2: return '01' - elif base == 10: return '0123456789' - elif base == 16: return "0123456789abcdef" - elif base == 58: return "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" - elif base == 256: return ''.join([chr(x) for x in range(256)]) - else: raise ValueError("Invalid base!") - -def encode(val,base,minlen=0): - code_string = get_code_string(base) - result = "" - while val > 0: - result = code_string[val % base] + result - val /= base - if len(result) < minlen: - result = code_string[0]*(minlen-len(result))+result - return result - -def decode(string,base): - code_string = get_code_string(base) - result = 0 - if base == 16: string = string.lower() - while len(string) > 0: - result *= base - result += code_string.find(string[0]) - string = string[1:] - return result - -def changebase(string,frm,to,minlen=0): - return encode(decode(string,frm),to,minlen) - -def base10_add(a,b): - if a == None: return b[0],b[1] - if b == None: return a[0],a[1] - if a[0] == b[0]: - if a[1] == b[1]: return base10_double(a[0],a[1]) - else: return None - m = ((b[1]-a[1]) * inv(b[0]-a[0],P)) % P - x = (m*m-a[0]-b[0]) % P - y = (m*(a[0]-x)-a[1]) % P - return (x,y) - -def base10_double(a): - if a == None: return None - m = ((3*a[0]*a[0]+A)*inv(2*a[1],P)) % P - x = (m*m-2*a[0]) % P - y = (m*(a[0]-x)-a[1]) % P - return (x,y) - -def base10_multiply(a,n): - if n == 0: return G - if n == 1: return a - if (n%2) == 0: return base10_double(base10_multiply(a,n/2)) - if (n%2) == 1: return base10_add(base10_double(base10_multiply(a,n/2)),a) - -def hex_to_point(h): return (decode(h[2:66],16),decode(h[66:],16)) - -def point_to_hex(p): return '04'+encode(p[0],16,64)+encode(p[1],16,64) - -def multiply(privkey,pubkey): - return point_to_hex(base10_multiply(hex_to_point(pubkey),decode(privkey,16))) - -def privtopub(privkey): - return point_to_hex(base10_multiply(G,decode(privkey,16))) - -def add(p1,p2): - if (len(p1)==32): - return encode(decode(p1,16) + decode(p2,16) % P,16,32) - else: - return point_to_hex(base10_add(hex_to_point(p1),hex_to_point(p2))) - -def hash_160(string): - intermed = hashlib.sha256(string).digest() - ripemd160 = hashlib.new('ripemd160') - ripemd160.update(intermed) - return ripemd160.digest() - -def dbl_sha256(string): - return hashlib.sha256(hashlib.sha256(string).digest()).digest() - -def bin_to_b58check(inp): - inp_fmtd = '\x00' + inp - leadingzbytes = len(re.match('^\x00*',inp_fmtd).group(0)) - checksum = dbl_sha256(inp_fmtd)[:4] - return '1' * leadingzbytes + changebase(inp_fmtd+checksum,256,58) - -#Convert a public key (in hex) to a Bitcoin address -def pubkey_to_address(pubkey): - return bin_to_b58check(hash_160(changebase(pubkey,16,256))) diff --git a/src/lib/pyelliptic/cipher.py b/src/lib/pyelliptic/cipher.py deleted file mode 100644 index b597cafa..00000000 --- a/src/lib/pyelliptic/cipher.py +++ /dev/null @@ -1,84 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# Copyright (C) 2011 Yann GUIBET -# See LICENSE for details. - -from pyelliptic.openssl import OpenSSL - - -class Cipher: - """ - Symmetric encryption - - import pyelliptic - iv = pyelliptic.Cipher.gen_IV('aes-256-cfb') - ctx = pyelliptic.Cipher("secretkey", iv, 1, ciphername='aes-256-cfb') - ciphertext = ctx.update('test1') - ciphertext += ctx.update('test2') - ciphertext += ctx.final() - - ctx2 = pyelliptic.Cipher("secretkey", iv, 0, ciphername='aes-256-cfb') - print ctx2.ciphering(ciphertext) - """ - def __init__(self, key, iv, do, ciphername='aes-256-cbc'): - """ - do == 1 => Encrypt; do == 0 => Decrypt - """ - self.cipher = OpenSSL.get_cipher(ciphername) - self.ctx = OpenSSL.EVP_CIPHER_CTX_new() - if do == 1 or do == 0: - k = OpenSSL.malloc(key, len(key)) - IV = OpenSSL.malloc(iv, len(iv)) - OpenSSL.EVP_CipherInit_ex( - self.ctx, self.cipher.get_pointer(), 0, k, IV, do) - else: - raise Exception("RTFM ...") - - @staticmethod - def get_all_cipher(): - """ - static method, returns all ciphers available - """ - return OpenSSL.cipher_algo.keys() - - @staticmethod - def get_blocksize(ciphername): - cipher = OpenSSL.get_cipher(ciphername) - return cipher.get_blocksize() - - @staticmethod - def gen_IV(ciphername): - cipher = OpenSSL.get_cipher(ciphername) - return OpenSSL.rand(cipher.get_blocksize()) - - def update(self, input): - i = OpenSSL.c_int(0) - buffer = OpenSSL.malloc(b"", len(input) + self.cipher.get_blocksize()) - inp = OpenSSL.malloc(input, len(input)) - if OpenSSL.EVP_CipherUpdate(self.ctx, OpenSSL.byref(buffer), - OpenSSL.byref(i), inp, len(input)) == 0: - raise Exception("[OpenSSL] EVP_CipherUpdate FAIL ...") - return buffer.raw[0:i.value] - - def final(self): - i = OpenSSL.c_int(0) - buffer = OpenSSL.malloc(b"", self.cipher.get_blocksize()) - if (OpenSSL.EVP_CipherFinal_ex(self.ctx, OpenSSL.byref(buffer), - OpenSSL.byref(i))) == 0: - raise Exception("[OpenSSL] EVP_CipherFinal_ex FAIL ...") - return buffer.raw[0:i.value] - - def ciphering(self, input): - """ - Do update and final in one method - """ - buff = self.update(input) - return buff + self.final() - - def __del__(self): - if OpenSSL._hexversion > 0x10100000 and not OpenSSL._libreSSL: - OpenSSL.EVP_CIPHER_CTX_reset(self.ctx) - else: - OpenSSL.EVP_CIPHER_CTX_cleanup(self.ctx) - OpenSSL.EVP_CIPHER_CTX_free(self.ctx) diff --git a/src/lib/pyelliptic/ecc.py b/src/lib/pyelliptic/ecc.py deleted file mode 100644 index bea645db..00000000 --- a/src/lib/pyelliptic/ecc.py +++ /dev/null @@ -1,480 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# Copyright (C) 2011 Yann GUIBET -# See LICENSE for details. - -from hashlib import sha512 -from pyelliptic.openssl import OpenSSL -from pyelliptic.cipher import Cipher -from pyelliptic.hash import hmac_sha256, equals -from struct import pack, unpack - - -class ECC: - """ - Asymmetric encryption with Elliptic Curve Cryptography (ECC) - ECDH, ECDSA and ECIES - - import pyelliptic - - alice = pyelliptic.ECC() # default curve: sect283r1 - bob = pyelliptic.ECC(curve='sect571r1') - - ciphertext = alice.encrypt("Hello Bob", bob.get_pubkey()) - print bob.decrypt(ciphertext) - - signature = bob.sign("Hello Alice") - # alice's job : - print pyelliptic.ECC( - pubkey=bob.get_pubkey()).verify(signature, "Hello Alice") - - # ERROR !!! - try: - key = alice.get_ecdh_key(bob.get_pubkey()) - except: print("For ECDH key agreement,\ - the keys must be defined on the same curve !") - - alice = pyelliptic.ECC(curve='sect571r1') - print alice.get_ecdh_key(bob.get_pubkey()).encode('hex') - print bob.get_ecdh_key(alice.get_pubkey()).encode('hex') - - """ - def __init__(self, pubkey=None, privkey=None, pubkey_x=None, - pubkey_y=None, raw_privkey=None, curve='sect283r1'): - """ - For a normal and High level use, specifie pubkey, - privkey (if you need) and the curve - """ - if type(curve) == str: - self.curve = OpenSSL.get_curve(curve) - else: - self.curve = curve - - if pubkey_x is not None and pubkey_y is not None: - self._set_keys(pubkey_x, pubkey_y, raw_privkey) - elif pubkey is not None: - curve, pubkey_x, pubkey_y, i = ECC._decode_pubkey(pubkey) - if privkey is not None: - curve2, raw_privkey, i = ECC._decode_privkey(privkey) - if curve != curve2: - raise Exception("Bad ECC keys ...") - self.curve = curve - self._set_keys(pubkey_x, pubkey_y, raw_privkey) - else: - self.privkey, self.pubkey_x, self.pubkey_y = self._generate() - - def _set_keys(self, pubkey_x, pubkey_y, privkey): - if self.raw_check_key(privkey, pubkey_x, pubkey_y) < 0: - self.pubkey_x = None - self.pubkey_y = None - self.privkey = None - raise Exception("Bad ECC keys ...") - else: - self.pubkey_x = pubkey_x - self.pubkey_y = pubkey_y - self.privkey = privkey - - @staticmethod - def get_curves(): - """ - static method, returns the list of all the curves available - """ - return OpenSSL.curves.keys() - - def get_curve(self): - return OpenSSL.get_curve_by_id(self.curve) - - def get_curve_id(self): - return self.curve - - def get_pubkey(self): - """ - High level function which returns : - curve(2) + len_of_pubkeyX(2) + pubkeyX + len_of_pubkeyY + pubkeyY - """ - return b''.join((pack('!H', self.curve), - pack('!H', len(self.pubkey_x)), - self.pubkey_x, - pack('!H', len(self.pubkey_y)), - self.pubkey_y - )) - - def get_privkey(self): - """ - High level function which returns - curve(2) + len_of_privkey(2) + privkey - """ - return b''.join((pack('!H', self.curve), - pack('!H', len(self.privkey)), - self.privkey - )) - - @staticmethod - def _decode_pubkey(pubkey): - i = 0 - curve = unpack('!H', pubkey[i:i + 2])[0] - i += 2 - tmplen = unpack('!H', pubkey[i:i + 2])[0] - i += 2 - pubkey_x = pubkey[i:i + tmplen] - i += tmplen - tmplen = unpack('!H', pubkey[i:i + 2])[0] - i += 2 - pubkey_y = pubkey[i:i + tmplen] - i += tmplen - return curve, pubkey_x, pubkey_y, i - - @staticmethod - def _decode_privkey(privkey): - i = 0 - curve = unpack('!H', privkey[i:i + 2])[0] - i += 2 - tmplen = unpack('!H', privkey[i:i + 2])[0] - i += 2 - privkey = privkey[i:i + tmplen] - i += tmplen - return curve, privkey, i - - def _generate(self): - try: - pub_key_x = OpenSSL.BN_new() - pub_key_y = OpenSSL.BN_new() - - key = OpenSSL.EC_KEY_new_by_curve_name(self.curve) - if key == 0: - raise Exception("[OpenSSL] EC_KEY_new_by_curve_name FAIL ...") - if (OpenSSL.EC_KEY_generate_key(key)) == 0: - raise Exception("[OpenSSL] EC_KEY_generate_key FAIL ...") - if (OpenSSL.EC_KEY_check_key(key)) == 0: - raise Exception("[OpenSSL] EC_KEY_check_key FAIL ...") - priv_key = OpenSSL.EC_KEY_get0_private_key(key) - - group = OpenSSL.EC_KEY_get0_group(key) - pub_key = OpenSSL.EC_KEY_get0_public_key(key) - - if (OpenSSL.EC_POINT_get_affine_coordinates_GFp(group, pub_key, - pub_key_x, - pub_key_y, 0 - )) == 0: - raise Exception( - "[OpenSSL] EC_POINT_get_affine_coordinates_GFp FAIL ...") - - privkey = OpenSSL.malloc(0, OpenSSL.BN_num_bytes(priv_key)) - pubkeyx = OpenSSL.malloc(0, OpenSSL.BN_num_bytes(pub_key_x)) - pubkeyy = OpenSSL.malloc(0, OpenSSL.BN_num_bytes(pub_key_y)) - OpenSSL.BN_bn2bin(priv_key, privkey) - privkey = privkey.raw - OpenSSL.BN_bn2bin(pub_key_x, pubkeyx) - pubkeyx = pubkeyx.raw - OpenSSL.BN_bn2bin(pub_key_y, pubkeyy) - pubkeyy = pubkeyy.raw - self.raw_check_key(privkey, pubkeyx, pubkeyy) - - return privkey, pubkeyx, pubkeyy - - finally: - OpenSSL.EC_KEY_free(key) - OpenSSL.BN_free(pub_key_x) - OpenSSL.BN_free(pub_key_y) - - def get_ecdh_key(self, pubkey): - """ - High level function. Compute public key with the local private key - and returns a 512bits shared key - """ - curve, pubkey_x, pubkey_y, i = ECC._decode_pubkey(pubkey) - if curve != self.curve: - raise Exception("ECC keys must be from the same curve !") - return sha512(self.raw_get_ecdh_key(pubkey_x, pubkey_y)).digest() - - def raw_get_ecdh_key(self, pubkey_x, pubkey_y): - try: - ecdh_keybuffer = OpenSSL.malloc(0, 32) - - other_key = OpenSSL.EC_KEY_new_by_curve_name(self.curve) - if other_key == 0: - raise Exception("[OpenSSL] EC_KEY_new_by_curve_name FAIL ...") - - other_pub_key_x = OpenSSL.BN_bin2bn(pubkey_x, len(pubkey_x), 0) - other_pub_key_y = OpenSSL.BN_bin2bn(pubkey_y, len(pubkey_y), 0) - - other_group = OpenSSL.EC_KEY_get0_group(other_key) - other_pub_key = OpenSSL.EC_POINT_new(other_group) - - if (OpenSSL.EC_POINT_set_affine_coordinates_GFp(other_group, - other_pub_key, - other_pub_key_x, - other_pub_key_y, - 0)) == 0: - raise Exception( - "[OpenSSL] EC_POINT_set_affine_coordinates_GFp FAIL ...") - if (OpenSSL.EC_KEY_set_public_key(other_key, other_pub_key)) == 0: - raise Exception("[OpenSSL] EC_KEY_set_public_key FAIL ...") - if (OpenSSL.EC_KEY_check_key(other_key)) == 0: - raise Exception("[OpenSSL] EC_KEY_check_key FAIL ...") - - own_key = OpenSSL.EC_KEY_new_by_curve_name(self.curve) - if own_key == 0: - raise Exception("[OpenSSL] EC_KEY_new_by_curve_name FAIL ...") - own_priv_key = OpenSSL.BN_bin2bn( - self.privkey, len(self.privkey), 0) - - if (OpenSSL.EC_KEY_set_private_key(own_key, own_priv_key)) == 0: - raise Exception("[OpenSSL] EC_KEY_set_private_key FAIL ...") - - if OpenSSL._hexversion > 0x10100000 and not OpenSSL._libreSSL: - OpenSSL.EC_KEY_set_method(own_key, OpenSSL.EC_KEY_OpenSSL()) - else: - OpenSSL.ECDH_set_method(own_key, OpenSSL.ECDH_OpenSSL()) - ecdh_keylen = OpenSSL.ECDH_compute_key( - ecdh_keybuffer, 32, other_pub_key, own_key, 0) - - if ecdh_keylen != 32: - raise Exception("[OpenSSL] ECDH keylen FAIL ...") - - return ecdh_keybuffer.raw - - finally: - OpenSSL.EC_KEY_free(other_key) - OpenSSL.BN_free(other_pub_key_x) - OpenSSL.BN_free(other_pub_key_y) - OpenSSL.EC_POINT_free(other_pub_key) - OpenSSL.EC_KEY_free(own_key) - OpenSSL.BN_free(own_priv_key) - - def check_key(self, privkey, pubkey): - """ - Check the public key and the private key. - The private key is optional (replace by None) - """ - curve, pubkey_x, pubkey_y, i = ECC._decode_pubkey(pubkey) - if privkey is None: - raw_privkey = None - curve2 = curve - else: - curve2, raw_privkey, i = ECC._decode_privkey(privkey) - if curve != curve2: - raise Exception("Bad public and private key") - return self.raw_check_key(raw_privkey, pubkey_x, pubkey_y, curve) - - def raw_check_key(self, privkey, pubkey_x, pubkey_y, curve=None): - if curve is None: - curve = self.curve - elif type(curve) == str: - curve = OpenSSL.get_curve(curve) - else: - curve = curve - try: - key = OpenSSL.EC_KEY_new_by_curve_name(curve) - if key == 0: - raise Exception("[OpenSSL] EC_KEY_new_by_curve_name FAIL ...") - if privkey is not None: - priv_key = OpenSSL.BN_bin2bn(privkey, len(privkey), 0) - pub_key_x = OpenSSL.BN_bin2bn(pubkey_x, len(pubkey_x), 0) - pub_key_y = OpenSSL.BN_bin2bn(pubkey_y, len(pubkey_y), 0) - - if privkey is not None: - if (OpenSSL.EC_KEY_set_private_key(key, priv_key)) == 0: - raise Exception( - "[OpenSSL] EC_KEY_set_private_key FAIL ...") - - group = OpenSSL.EC_KEY_get0_group(key) - pub_key = OpenSSL.EC_POINT_new(group) - - if (OpenSSL.EC_POINT_set_affine_coordinates_GFp(group, pub_key, - pub_key_x, - pub_key_y, - 0)) == 0: - raise Exception( - "[OpenSSL] EC_POINT_set_affine_coordinates_GFp FAIL ...") - if (OpenSSL.EC_KEY_set_public_key(key, pub_key)) == 0: - raise Exception("[OpenSSL] EC_KEY_set_public_key FAIL ...") - if (OpenSSL.EC_KEY_check_key(key)) == 0: - raise Exception("[OpenSSL] EC_KEY_check_key FAIL ...") - return 0 - - finally: - OpenSSL.EC_KEY_free(key) - OpenSSL.BN_free(pub_key_x) - OpenSSL.BN_free(pub_key_y) - OpenSSL.EC_POINT_free(pub_key) - if privkey is not None: - OpenSSL.BN_free(priv_key) - - def sign(self, inputb, digest_alg=OpenSSL.digest_ecdsa_sha1): - """ - Sign the input with ECDSA method and returns the signature - """ - try: - size = len(inputb) - buff = OpenSSL.malloc(inputb, size) - digest = OpenSSL.malloc(0, 64) - if OpenSSL._hexversion > 0x10100000 and not OpenSSL._libreSSL: - md_ctx = OpenSSL.EVP_MD_CTX_new() - else: - md_ctx = OpenSSL.EVP_MD_CTX_create() - dgst_len = OpenSSL.pointer(OpenSSL.c_int(0)) - siglen = OpenSSL.pointer(OpenSSL.c_int(0)) - sig = OpenSSL.malloc(0, 151) - - key = OpenSSL.EC_KEY_new_by_curve_name(self.curve) - if key == 0: - raise Exception("[OpenSSL] EC_KEY_new_by_curve_name FAIL ...") - - priv_key = OpenSSL.BN_bin2bn(self.privkey, len(self.privkey), 0) - pub_key_x = OpenSSL.BN_bin2bn(self.pubkey_x, len(self.pubkey_x), 0) - pub_key_y = OpenSSL.BN_bin2bn(self.pubkey_y, len(self.pubkey_y), 0) - - if (OpenSSL.EC_KEY_set_private_key(key, priv_key)) == 0: - raise Exception("[OpenSSL] EC_KEY_set_private_key FAIL ...") - - group = OpenSSL.EC_KEY_get0_group(key) - pub_key = OpenSSL.EC_POINT_new(group) - - if (OpenSSL.EC_POINT_set_affine_coordinates_GFp(group, pub_key, - pub_key_x, - pub_key_y, - 0)) == 0: - raise Exception( - "[OpenSSL] EC_POINT_set_affine_coordinates_GFp FAIL ...") - if (OpenSSL.EC_KEY_set_public_key(key, pub_key)) == 0: - raise Exception("[OpenSSL] EC_KEY_set_public_key FAIL ...") - if (OpenSSL.EC_KEY_check_key(key)) == 0: - raise Exception("[OpenSSL] EC_KEY_check_key FAIL ...") - - if OpenSSL._hexversion > 0x10100000 and not OpenSSL._libreSSL: - OpenSSL.EVP_MD_CTX_new(md_ctx) - else: - OpenSSL.EVP_MD_CTX_init(md_ctx) - OpenSSL.EVP_DigestInit_ex(md_ctx, digest_alg(), None) - - if (OpenSSL.EVP_DigestUpdate(md_ctx, buff, size)) == 0: - raise Exception("[OpenSSL] EVP_DigestUpdate FAIL ...") - OpenSSL.EVP_DigestFinal_ex(md_ctx, digest, dgst_len) - OpenSSL.ECDSA_sign(0, digest, dgst_len.contents, sig, siglen, key) - if (OpenSSL.ECDSA_verify(0, digest, dgst_len.contents, sig, - siglen.contents, key)) != 1: - raise Exception("[OpenSSL] ECDSA_verify FAIL ...") - - return sig.raw[:siglen.contents.value] - - finally: - OpenSSL.EC_KEY_free(key) - OpenSSL.BN_free(pub_key_x) - OpenSSL.BN_free(pub_key_y) - OpenSSL.BN_free(priv_key) - OpenSSL.EC_POINT_free(pub_key) - if OpenSSL._hexversion > 0x10100000 and not OpenSSL._libreSSL: - OpenSSL.EVP_MD_CTX_free(md_ctx) - else: - OpenSSL.EVP_MD_CTX_destroy(md_ctx) - pass - - def verify(self, sig, inputb, digest_alg=OpenSSL.digest_ecdsa_sha1): - """ - Verify the signature with the input and the local public key. - Returns a boolean - """ - try: - bsig = OpenSSL.malloc(sig, len(sig)) - binputb = OpenSSL.malloc(inputb, len(inputb)) - digest = OpenSSL.malloc(0, 64) - dgst_len = OpenSSL.pointer(OpenSSL.c_int(0)) - if OpenSSL._hexversion > 0x10100000 and not OpenSSL._libreSSL: - md_ctx = OpenSSL.EVP_MD_CTX_new() - else: - md_ctx = OpenSSL.EVP_MD_CTX_create() - key = OpenSSL.EC_KEY_new_by_curve_name(self.curve) - - if key == 0: - raise Exception("[OpenSSL] EC_KEY_new_by_curve_name FAIL ...") - - pub_key_x = OpenSSL.BN_bin2bn(self.pubkey_x, len(self.pubkey_x), 0) - pub_key_y = OpenSSL.BN_bin2bn(self.pubkey_y, len(self.pubkey_y), 0) - group = OpenSSL.EC_KEY_get0_group(key) - pub_key = OpenSSL.EC_POINT_new(group) - - if (OpenSSL.EC_POINT_set_affine_coordinates_GFp(group, pub_key, - pub_key_x, - pub_key_y, - 0)) == 0: - raise Exception( - "[OpenSSL] EC_POINT_set_affine_coordinates_GFp FAIL ...") - if (OpenSSL.EC_KEY_set_public_key(key, pub_key)) == 0: - raise Exception("[OpenSSL] EC_KEY_set_public_key FAIL ...") - if (OpenSSL.EC_KEY_check_key(key)) == 0: - raise Exception("[OpenSSL] EC_KEY_check_key FAIL ...") - if OpenSSL._hexversion > 0x10100000 and not OpenSSL._libreSSL: - OpenSSL.EVP_MD_CTX_new(md_ctx) - else: - OpenSSL.EVP_MD_CTX_init(md_ctx) - OpenSSL.EVP_DigestInit_ex(md_ctx, digest_alg(), None) - if (OpenSSL.EVP_DigestUpdate(md_ctx, binputb, len(inputb))) == 0: - raise Exception("[OpenSSL] EVP_DigestUpdate FAIL ...") - - OpenSSL.EVP_DigestFinal_ex(md_ctx, digest, dgst_len) - ret = OpenSSL.ECDSA_verify( - 0, digest, dgst_len.contents, bsig, len(sig), key) - - if ret == -1: - return False # Fail to Check - else: - if ret == 0: - return False # Bad signature ! - else: - return True # Good - return False - - finally: - OpenSSL.EC_KEY_free(key) - OpenSSL.BN_free(pub_key_x) - OpenSSL.BN_free(pub_key_y) - OpenSSL.EC_POINT_free(pub_key) - if OpenSSL._hexversion > 0x10100000 and not OpenSSL._libreSSL: - OpenSSL.EVP_MD_CTX_free(md_ctx) - else: - OpenSSL.EVP_MD_CTX_destroy(md_ctx) - - @staticmethod - def encrypt(data, pubkey, ephemcurve=None, ciphername='aes-256-cbc'): - """ - Encrypt data with ECIES method using the public key of the recipient. - """ - curve, pubkey_x, pubkey_y, i = ECC._decode_pubkey(pubkey) - return ECC.raw_encrypt(data, pubkey_x, pubkey_y, curve=curve, - ephemcurve=ephemcurve, ciphername=ciphername) - - @staticmethod - def raw_encrypt(data, pubkey_x, pubkey_y, curve='sect283r1', - ephemcurve=None, ciphername='aes-256-cbc'): - if ephemcurve is None: - ephemcurve = curve - ephem = ECC(curve=ephemcurve) - key = sha512(ephem.raw_get_ecdh_key(pubkey_x, pubkey_y)).digest() - key_e, key_m = key[:32], key[32:] - pubkey = ephem.get_pubkey() - iv = OpenSSL.rand(OpenSSL.get_cipher(ciphername).get_blocksize()) - ctx = Cipher(key_e, iv, 1, ciphername) - ciphertext = iv + pubkey + ctx.ciphering(data) - mac = hmac_sha256(key_m, ciphertext) - return ciphertext + mac - - def decrypt(self, data, ciphername='aes-256-cbc'): - """ - Decrypt data with ECIES method using the local private key - """ - blocksize = OpenSSL.get_cipher(ciphername).get_blocksize() - iv = data[:blocksize] - i = blocksize - curve, pubkey_x, pubkey_y, i2 = ECC._decode_pubkey(data[i:]) - i += i2 - ciphertext = data[i:len(data)-32] - i += len(ciphertext) - mac = data[i:] - key = sha512(self.raw_get_ecdh_key(pubkey_x, pubkey_y)).digest() - key_e, key_m = key[:32], key[32:] - if not equals(hmac_sha256(key_m, data[:len(data) - 32]), mac): - raise RuntimeError("Fail to verify data") - ctx = Cipher(key_e, iv, 0, ciphername) - return ctx.ciphering(ciphertext) diff --git a/src/lib/pyelliptic/hash.py b/src/lib/pyelliptic/hash.py deleted file mode 100644 index fb910dd4..00000000 --- a/src/lib/pyelliptic/hash.py +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# Copyright (C) 2011 Yann GUIBET -# See LICENSE for details. - -from pyelliptic.openssl import OpenSSL - - -# For python3 -def _equals_bytes(a, b): - if len(a) != len(b): - return False - result = 0 - for x, y in zip(a, b): - result |= x ^ y - return result == 0 - - -def _equals_str(a, b): - if len(a) != len(b): - return False - result = 0 - for x, y in zip(a, b): - result |= ord(x) ^ ord(y) - return result == 0 - - -def equals(a, b): - if isinstance(a, str): - return _equals_str(a, b) - else: - return _equals_bytes(a, b) - - -def hmac_sha256(k, m): - """ - Compute the key and the message with HMAC SHA5256 - """ - key = OpenSSL.malloc(k, len(k)) - d = OpenSSL.malloc(m, len(m)) - md = OpenSSL.malloc(0, 32) - i = OpenSSL.pointer(OpenSSL.c_int(0)) - OpenSSL.HMAC(OpenSSL.EVP_sha256(), key, len(k), d, len(m), md, i) - return md.raw - - -def hmac_sha512(k, m): - """ - Compute the key and the message with HMAC SHA512 - """ - key = OpenSSL.malloc(k, len(k)) - d = OpenSSL.malloc(m, len(m)) - md = OpenSSL.malloc(0, 64) - i = OpenSSL.pointer(OpenSSL.c_int(0)) - OpenSSL.HMAC(OpenSSL.EVP_sha512(), key, len(k), d, len(m), md, i) - return md.raw - - -def pbkdf2(password, salt=None, i=10000, keylen=64): - if salt is None: - salt = OpenSSL.rand(8) - p_password = OpenSSL.malloc(password, len(password)) - p_salt = OpenSSL.malloc(salt, len(salt)) - output = OpenSSL.malloc(0, keylen) - OpenSSL.PKCS5_PBKDF2_HMAC(p_password, len(password), p_salt, - len(p_salt), i, OpenSSL.EVP_sha256(), - keylen, output) - return salt, output.raw diff --git a/src/lib/pyelliptic/openssl.py b/src/lib/pyelliptic/openssl.py deleted file mode 100644 index 6043f404..00000000 --- a/src/lib/pyelliptic/openssl.py +++ /dev/null @@ -1,504 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# Copyright (C) 2011 Yann GUIBET -# See LICENSE for details. -# -# Software slightly changed by Jonathan Warren - -import sys -import ctypes - -OpenSSL = None - - -class CipherName: - def __init__(self, name, pointer, blocksize): - self._name = name - self._pointer = pointer - self._blocksize = blocksize - - def __str__(self): - return "Cipher : " + self._name + " | Blocksize : " + str(self._blocksize) + " | Fonction pointer : " + str(self._pointer) - - def get_pointer(self): - return self._pointer() - - def get_name(self): - return self._name - - def get_blocksize(self): - return self._blocksize - - -def get_version(library): - version = None - hexversion = None - cflags = None - try: - #OpenSSL 1.1 - OPENSSL_VERSION = 0 - OPENSSL_CFLAGS = 1 - library.OpenSSL_version.argtypes = [ctypes.c_int] - library.OpenSSL_version.restype = ctypes.c_char_p - version = library.OpenSSL_version(OPENSSL_VERSION) - cflags = library.OpenSSL_version(OPENSSL_CFLAGS) - library.OpenSSL_version_num.restype = ctypes.c_long - hexversion = library.OpenSSL_version_num() - except AttributeError: - try: - #OpenSSL 1.0 - SSLEAY_VERSION = 0 - SSLEAY_CFLAGS = 2 - library.SSLeay.restype = ctypes.c_long - library.SSLeay_version.restype = ctypes.c_char_p - library.SSLeay_version.argtypes = [ctypes.c_int] - version = library.SSLeay_version(SSLEAY_VERSION) - cflags = library.SSLeay_version(SSLEAY_CFLAGS) - hexversion = library.SSLeay() - except AttributeError: - #raise NotImplementedError('Cannot determine version of this OpenSSL library.') - pass - return (version, hexversion, cflags) - - -class _OpenSSL: - """ - Wrapper for OpenSSL using ctypes - """ - def __init__(self, library): - """ - Build the wrapper - """ - self._lib = ctypes.CDLL(library) - self._version, self._hexversion, self._cflags = get_version(self._lib) - self._libreSSL = self._version.startswith("LibreSSL") - - self.pointer = ctypes.pointer - self.c_int = ctypes.c_int - self.byref = ctypes.byref - self.create_string_buffer = ctypes.create_string_buffer - - self.BN_new = self._lib.BN_new - self.BN_new.restype = ctypes.c_void_p - self.BN_new.argtypes = [] - - self.BN_free = self._lib.BN_free - self.BN_free.restype = None - self.BN_free.argtypes = [ctypes.c_void_p] - - self.BN_num_bits = self._lib.BN_num_bits - self.BN_num_bits.restype = ctypes.c_int - self.BN_num_bits.argtypes = [ctypes.c_void_p] - - self.BN_bn2bin = self._lib.BN_bn2bin - self.BN_bn2bin.restype = ctypes.c_int - self.BN_bn2bin.argtypes = [ctypes.c_void_p, ctypes.c_void_p] - - self.BN_bin2bn = self._lib.BN_bin2bn - self.BN_bin2bn.restype = ctypes.c_void_p - self.BN_bin2bn.argtypes = [ctypes.c_void_p, ctypes.c_int, - ctypes.c_void_p] - - self.EC_KEY_free = self._lib.EC_KEY_free - self.EC_KEY_free.restype = None - self.EC_KEY_free.argtypes = [ctypes.c_void_p] - - self.EC_KEY_new_by_curve_name = self._lib.EC_KEY_new_by_curve_name - self.EC_KEY_new_by_curve_name.restype = ctypes.c_void_p - self.EC_KEY_new_by_curve_name.argtypes = [ctypes.c_int] - - self.EC_KEY_generate_key = self._lib.EC_KEY_generate_key - self.EC_KEY_generate_key.restype = ctypes.c_int - self.EC_KEY_generate_key.argtypes = [ctypes.c_void_p] - - self.EC_KEY_check_key = self._lib.EC_KEY_check_key - self.EC_KEY_check_key.restype = ctypes.c_int - self.EC_KEY_check_key.argtypes = [ctypes.c_void_p] - - self.EC_KEY_get0_private_key = self._lib.EC_KEY_get0_private_key - self.EC_KEY_get0_private_key.restype = ctypes.c_void_p - self.EC_KEY_get0_private_key.argtypes = [ctypes.c_void_p] - - self.EC_KEY_get0_public_key = self._lib.EC_KEY_get0_public_key - self.EC_KEY_get0_public_key.restype = ctypes.c_void_p - self.EC_KEY_get0_public_key.argtypes = [ctypes.c_void_p] - - self.EC_KEY_get0_group = self._lib.EC_KEY_get0_group - self.EC_KEY_get0_group.restype = ctypes.c_void_p - self.EC_KEY_get0_group.argtypes = [ctypes.c_void_p] - - self.EC_POINT_get_affine_coordinates_GFp = self._lib.EC_POINT_get_affine_coordinates_GFp - self.EC_POINT_get_affine_coordinates_GFp.restype = ctypes.c_int - self.EC_POINT_get_affine_coordinates_GFp.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p] - - self.EC_KEY_set_private_key = self._lib.EC_KEY_set_private_key - self.EC_KEY_set_private_key.restype = ctypes.c_int - self.EC_KEY_set_private_key.argtypes = [ctypes.c_void_p, - ctypes.c_void_p] - - self.EC_KEY_set_public_key = self._lib.EC_KEY_set_public_key - self.EC_KEY_set_public_key.restype = ctypes.c_int - self.EC_KEY_set_public_key.argtypes = [ctypes.c_void_p, - ctypes.c_void_p] - - self.EC_KEY_set_group = self._lib.EC_KEY_set_group - self.EC_KEY_set_group.restype = ctypes.c_int - self.EC_KEY_set_group.argtypes = [ctypes.c_void_p, ctypes.c_void_p] - - self.EC_POINT_set_affine_coordinates_GFp = self._lib.EC_POINT_set_affine_coordinates_GFp - self.EC_POINT_set_affine_coordinates_GFp.restype = ctypes.c_int - self.EC_POINT_set_affine_coordinates_GFp.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p] - - self.EC_POINT_new = self._lib.EC_POINT_new - self.EC_POINT_new.restype = ctypes.c_void_p - self.EC_POINT_new.argtypes = [ctypes.c_void_p] - - self.EC_POINT_free = self._lib.EC_POINT_free - self.EC_POINT_free.restype = None - self.EC_POINT_free.argtypes = [ctypes.c_void_p] - - self.BN_CTX_free = self._lib.BN_CTX_free - self.BN_CTX_free.restype = None - self.BN_CTX_free.argtypes = [ctypes.c_void_p] - - self.EC_POINT_mul = self._lib.EC_POINT_mul - self.EC_POINT_mul.restype = None - self.EC_POINT_mul.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p] - - self.EC_KEY_set_private_key = self._lib.EC_KEY_set_private_key - self.EC_KEY_set_private_key.restype = ctypes.c_int - self.EC_KEY_set_private_key.argtypes = [ctypes.c_void_p, - ctypes.c_void_p] - - if self._hexversion >= 0x10100000 and not self._libreSSL: - self.EC_KEY_OpenSSL = self._lib.EC_KEY_OpenSSL - self._lib.EC_KEY_OpenSSL.restype = ctypes.c_void_p - self._lib.EC_KEY_OpenSSL.argtypes = [] - - self.EC_KEY_set_method = self._lib.EC_KEY_set_method - self._lib.EC_KEY_set_method.restype = ctypes.c_int - self._lib.EC_KEY_set_method.argtypes = [ctypes.c_void_p, ctypes.c_void_p] - else: - self.ECDH_OpenSSL = self._lib.ECDH_OpenSSL - self._lib.ECDH_OpenSSL.restype = ctypes.c_void_p - self._lib.ECDH_OpenSSL.argtypes = [] - - self.ECDH_set_method = self._lib.ECDH_set_method - self._lib.ECDH_set_method.restype = ctypes.c_int - self._lib.ECDH_set_method.argtypes = [ctypes.c_void_p, ctypes.c_void_p] - - self.BN_CTX_new = self._lib.BN_CTX_new - self._lib.BN_CTX_new.restype = ctypes.c_void_p - self._lib.BN_CTX_new.argtypes = [] - - self.ECDH_compute_key = self._lib.ECDH_compute_key - self.ECDH_compute_key.restype = ctypes.c_int - self.ECDH_compute_key.argtypes = [ctypes.c_void_p, - ctypes.c_int, ctypes.c_void_p, ctypes.c_void_p] - - self.EVP_CipherInit_ex = self._lib.EVP_CipherInit_ex - self.EVP_CipherInit_ex.restype = ctypes.c_int - self.EVP_CipherInit_ex.argtypes = [ctypes.c_void_p, - ctypes.c_void_p, ctypes.c_void_p] - - self.EVP_CIPHER_CTX_new = self._lib.EVP_CIPHER_CTX_new - self.EVP_CIPHER_CTX_new.restype = ctypes.c_void_p - self.EVP_CIPHER_CTX_new.argtypes = [] - - # Cipher - self.EVP_aes_128_cfb128 = self._lib.EVP_aes_128_cfb128 - self.EVP_aes_128_cfb128.restype = ctypes.c_void_p - self.EVP_aes_128_cfb128.argtypes = [] - - self.EVP_aes_256_cfb128 = self._lib.EVP_aes_256_cfb128 - self.EVP_aes_256_cfb128.restype = ctypes.c_void_p - self.EVP_aes_256_cfb128.argtypes = [] - - self.EVP_aes_128_cbc = self._lib.EVP_aes_128_cbc - self.EVP_aes_128_cbc.restype = ctypes.c_void_p - self.EVP_aes_128_cbc.argtypes = [] - - self.EVP_aes_256_cbc = self._lib.EVP_aes_256_cbc - self.EVP_aes_256_cbc.restype = ctypes.c_void_p - self.EVP_aes_256_cbc.argtypes = [] - - #self.EVP_aes_128_ctr = self._lib.EVP_aes_128_ctr - #self.EVP_aes_128_ctr.restype = ctypes.c_void_p - #self.EVP_aes_128_ctr.argtypes = [] - - #self.EVP_aes_256_ctr = self._lib.EVP_aes_256_ctr - #self.EVP_aes_256_ctr.restype = ctypes.c_void_p - #self.EVP_aes_256_ctr.argtypes = [] - - self.EVP_aes_128_ofb = self._lib.EVP_aes_128_ofb - self.EVP_aes_128_ofb.restype = ctypes.c_void_p - self.EVP_aes_128_ofb.argtypes = [] - - self.EVP_aes_256_ofb = self._lib.EVP_aes_256_ofb - self.EVP_aes_256_ofb.restype = ctypes.c_void_p - self.EVP_aes_256_ofb.argtypes = [] - - self.EVP_bf_cbc = self._lib.EVP_bf_cbc - self.EVP_bf_cbc.restype = ctypes.c_void_p - self.EVP_bf_cbc.argtypes = [] - - self.EVP_bf_cfb64 = self._lib.EVP_bf_cfb64 - self.EVP_bf_cfb64.restype = ctypes.c_void_p - self.EVP_bf_cfb64.argtypes = [] - - self.EVP_rc4 = self._lib.EVP_rc4 - self.EVP_rc4.restype = ctypes.c_void_p - self.EVP_rc4.argtypes = [] - - if self._hexversion >= 0x10100000 and not self._libreSSL: - self.EVP_CIPHER_CTX_reset = self._lib.EVP_CIPHER_CTX_reset - self.EVP_CIPHER_CTX_reset.restype = ctypes.c_int - self.EVP_CIPHER_CTX_reset.argtypes = [ctypes.c_void_p] - else: - self.EVP_CIPHER_CTX_cleanup = self._lib.EVP_CIPHER_CTX_cleanup - self.EVP_CIPHER_CTX_cleanup.restype = ctypes.c_int - self.EVP_CIPHER_CTX_cleanup.argtypes = [ctypes.c_void_p] - - self.EVP_CIPHER_CTX_free = self._lib.EVP_CIPHER_CTX_free - self.EVP_CIPHER_CTX_free.restype = None - self.EVP_CIPHER_CTX_free.argtypes = [ctypes.c_void_p] - - self.EVP_CipherUpdate = self._lib.EVP_CipherUpdate - self.EVP_CipherUpdate.restype = ctypes.c_int - self.EVP_CipherUpdate.argtypes = [ctypes.c_void_p, - ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int] - - self.EVP_CipherFinal_ex = self._lib.EVP_CipherFinal_ex - self.EVP_CipherFinal_ex.restype = ctypes.c_int - self.EVP_CipherFinal_ex.argtypes = [ctypes.c_void_p, - ctypes.c_void_p, ctypes.c_void_p] - - self.EVP_DigestInit = self._lib.EVP_DigestInit - self.EVP_DigestInit.restype = ctypes.c_int - self._lib.EVP_DigestInit.argtypes = [ctypes.c_void_p, ctypes.c_void_p] - - self.EVP_DigestInit_ex = self._lib.EVP_DigestInit_ex - self.EVP_DigestInit_ex.restype = ctypes.c_int - self._lib.EVP_DigestInit_ex.argtypes = 3 * [ctypes.c_void_p] - - self.EVP_DigestUpdate = self._lib.EVP_DigestUpdate - self.EVP_DigestUpdate.restype = ctypes.c_int - self.EVP_DigestUpdate.argtypes = [ctypes.c_void_p, - ctypes.c_void_p, ctypes.c_int] - - self.EVP_DigestFinal = self._lib.EVP_DigestFinal - self.EVP_DigestFinal.restype = ctypes.c_int - self.EVP_DigestFinal.argtypes = [ctypes.c_void_p, - ctypes.c_void_p, ctypes.c_void_p] - - self.EVP_DigestFinal_ex = self._lib.EVP_DigestFinal_ex - self.EVP_DigestFinal_ex.restype = ctypes.c_int - self.EVP_DigestFinal_ex.argtypes = [ctypes.c_void_p, - ctypes.c_void_p, ctypes.c_void_p] - - self.ECDSA_sign = self._lib.ECDSA_sign - self.ECDSA_sign.restype = ctypes.c_int - self.ECDSA_sign.argtypes = [ctypes.c_int, ctypes.c_void_p, - ctypes.c_int, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p] - - self.ECDSA_verify = self._lib.ECDSA_verify - self.ECDSA_verify.restype = ctypes.c_int - self.ECDSA_verify.argtypes = [ctypes.c_int, ctypes.c_void_p, - ctypes.c_int, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p] - - if self._hexversion >= 0x10100000 and not self._libreSSL: - self.EVP_MD_CTX_new = self._lib.EVP_MD_CTX_new - self.EVP_MD_CTX_new.restype = ctypes.c_void_p - self.EVP_MD_CTX_new.argtypes = [] - - self.EVP_MD_CTX_reset = self._lib.EVP_MD_CTX_reset - self.EVP_MD_CTX_reset.restype = None - self.EVP_MD_CTX_reset.argtypes = [ctypes.c_void_p] - - self.EVP_MD_CTX_free = self._lib.EVP_MD_CTX_free - self.EVP_MD_CTX_free.restype = None - self.EVP_MD_CTX_free.argtypes = [ctypes.c_void_p] - - self.EVP_sha1 = self._lib.EVP_sha1 - self.EVP_sha1.restype = ctypes.c_void_p - self.EVP_sha1.argtypes = [] - - self.digest_ecdsa_sha1 = self.EVP_sha1 - else: - self.EVP_MD_CTX_create = self._lib.EVP_MD_CTX_create - self.EVP_MD_CTX_create.restype = ctypes.c_void_p - self.EVP_MD_CTX_create.argtypes = [] - - self.EVP_MD_CTX_init = self._lib.EVP_MD_CTX_init - self.EVP_MD_CTX_init.restype = None - self.EVP_MD_CTX_init.argtypes = [ctypes.c_void_p] - - self.EVP_MD_CTX_destroy = self._lib.EVP_MD_CTX_destroy - self.EVP_MD_CTX_destroy.restype = None - self.EVP_MD_CTX_destroy.argtypes = [ctypes.c_void_p] - - self.EVP_ecdsa = self._lib.EVP_ecdsa - self._lib.EVP_ecdsa.restype = ctypes.c_void_p - self._lib.EVP_ecdsa.argtypes = [] - - self.digest_ecdsa_sha1 = self.EVP_ecdsa - - self.RAND_bytes = self._lib.RAND_bytes - self.RAND_bytes.restype = ctypes.c_int - self.RAND_bytes.argtypes = [ctypes.c_void_p, ctypes.c_int] - - self.EVP_sha256 = self._lib.EVP_sha256 - self.EVP_sha256.restype = ctypes.c_void_p - self.EVP_sha256.argtypes = [] - - self.i2o_ECPublicKey = self._lib.i2o_ECPublicKey - self.i2o_ECPublicKey.restype = ctypes.c_void_p - self.i2o_ECPublicKey.argtypes = [ctypes.c_void_p, ctypes.c_void_p] - - self.EVP_sha512 = self._lib.EVP_sha512 - self.EVP_sha512.restype = ctypes.c_void_p - self.EVP_sha512.argtypes = [] - - self.HMAC = self._lib.HMAC - self.HMAC.restype = ctypes.c_void_p - self.HMAC.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int, - ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_void_p] - - try: - self.PKCS5_PBKDF2_HMAC = self._lib.PKCS5_PBKDF2_HMAC - except: - # The above is not compatible with all versions of OSX. - self.PKCS5_PBKDF2_HMAC = self._lib.PKCS5_PBKDF2_HMAC_SHA1 - - self.PKCS5_PBKDF2_HMAC.restype = ctypes.c_int - self.PKCS5_PBKDF2_HMAC.argtypes = [ctypes.c_void_p, ctypes.c_int, - ctypes.c_void_p, ctypes.c_int, - ctypes.c_int, ctypes.c_void_p, - ctypes.c_int, ctypes.c_void_p] - - self._set_ciphers() - self._set_curves() - - def _set_ciphers(self): - self.cipher_algo = { - 'aes-128-cbc': CipherName('aes-128-cbc', self.EVP_aes_128_cbc, 16), - 'aes-256-cbc': CipherName('aes-256-cbc', self.EVP_aes_256_cbc, 16), - 'aes-128-cfb': CipherName('aes-128-cfb', self.EVP_aes_128_cfb128, 16), - 'aes-256-cfb': CipherName('aes-256-cfb', self.EVP_aes_256_cfb128, 16), - 'aes-128-ofb': CipherName('aes-128-ofb', self._lib.EVP_aes_128_ofb, 16), - 'aes-256-ofb': CipherName('aes-256-ofb', self._lib.EVP_aes_256_ofb, 16), - #'aes-128-ctr': CipherName('aes-128-ctr', self._lib.EVP_aes_128_ctr, 16), - #'aes-256-ctr': CipherName('aes-256-ctr', self._lib.EVP_aes_256_ctr, 16), - 'bf-cfb': CipherName('bf-cfb', self.EVP_bf_cfb64, 8), - 'bf-cbc': CipherName('bf-cbc', self.EVP_bf_cbc, 8), - 'rc4': CipherName('rc4', self.EVP_rc4, 128), # 128 is the initialisation size not block size - } - - def _set_curves(self): - self.curves = { - 'secp112r1': 704, - 'secp112r2': 705, - 'secp128r1': 706, - 'secp128r2': 707, - 'secp160k1': 708, - 'secp160r1': 709, - 'secp160r2': 710, - 'secp192k1': 711, - 'secp224k1': 712, - 'secp224r1': 713, - 'secp256k1': 714, - 'secp384r1': 715, - 'secp521r1': 716, - 'sect113r1': 717, - 'sect113r2': 718, - 'sect131r1': 719, - 'sect131r2': 720, - 'sect163k1': 721, - 'sect163r1': 722, - 'sect163r2': 723, - 'sect193r1': 724, - 'sect193r2': 725, - 'sect233k1': 726, - 'sect233r1': 727, - 'sect239k1': 728, - 'sect283k1': 729, - 'sect283r1': 730, - 'sect409k1': 731, - 'sect409r1': 732, - 'sect571k1': 733, - 'sect571r1': 734, - } - - def BN_num_bytes(self, x): - """ - returns the length of a BN (OpenSSl API) - """ - return int((self.BN_num_bits(x) + 7) / 8) - - def get_cipher(self, name): - """ - returns the OpenSSL cipher instance - """ - if name not in self.cipher_algo: - raise Exception("Unknown cipher") - return self.cipher_algo[name] - - def get_curve(self, name): - """ - returns the id of a elliptic curve - """ - if name not in self.curves: - raise Exception("Unknown curve") - return self.curves[name] - - def get_curve_by_id(self, id): - """ - returns the name of a elliptic curve with his id - """ - res = None - for i in self.curves: - if self.curves[i] == id: - res = i - break - if res is None: - raise Exception("Unknown curve") - return res - - def rand(self, size): - """ - OpenSSL random function - """ - buffer = self.malloc(0, size) - # This pyelliptic library, by default, didn't check the return value of RAND_bytes. It is - # evidently possible that it returned an error and not-actually-random data. However, in - # tests on various operating systems, while generating hundreds of gigabytes of random - # strings of various sizes I could not get an error to occur. Also Bitcoin doesn't check - # the return value of RAND_bytes either. - # Fixed in Bitmessage version 0.4.2 (in source code on 2013-10-13) - while self.RAND_bytes(buffer, size) != 1: - import time - time.sleep(1) - return buffer.raw - - def malloc(self, data, size): - """ - returns a create_string_buffer (ctypes) - """ - buffer = None - if data != 0: - if sys.version_info.major == 3 and isinstance(data, type('')): - data = data.encode() - buffer = self.create_string_buffer(data, size) - else: - buffer = self.create_string_buffer(size) - return buffer - -def loadOpenSSL(): - import logging - import util.SslPatch - global OpenSSL - OpenSSL = _OpenSSL(util.SslPatch.getLibraryPath()) - logging.debug("pyelliptic loaded: %s", OpenSSL._lib) - -loadOpenSSL() diff --git a/src/lib/rsa/LICENSE b/src/lib/rsa/LICENSE deleted file mode 100644 index da76c9d7..00000000 --- a/src/lib/rsa/LICENSE +++ /dev/null @@ -1,13 +0,0 @@ -Copyright 2011 Sybren A. Stüvel - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/src/lib/rsa/__init__.py b/src/lib/rsa/__init__.py deleted file mode 100644 index c572c06b..00000000 --- a/src/lib/rsa/__init__.py +++ /dev/null @@ -1,42 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2011 Sybren A. Stüvel -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -"""RSA module - -Module for calculating large primes, and RSA encryption, decryption, signing -and verification. Includes generating public and private keys. - -WARNING: this implementation does not use random padding, compression of the -cleartext input to prevent repetitions, or other common security improvements. -Use with care. - -""" - -from rsa.key import newkeys, PrivateKey, PublicKey -from rsa.pkcs1 import encrypt, decrypt, sign, verify, DecryptionError, \ - VerificationError - -__author__ = "Sybren Stuvel, Barry Mead and Yesudeep Mangalapilly" -__date__ = "2016-03-29" -__version__ = '3.4.2' - -# Do doctest if we're run directly -if __name__ == "__main__": - import doctest - - doctest.testmod() - -__all__ = ["newkeys", "encrypt", "decrypt", "sign", "verify", 'PublicKey', - 'PrivateKey', 'DecryptionError', 'VerificationError'] diff --git a/src/lib/rsa/_compat.py b/src/lib/rsa/_compat.py deleted file mode 100644 index 93393d9f..00000000 --- a/src/lib/rsa/_compat.py +++ /dev/null @@ -1,148 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2011 Sybren A. Stüvel -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Python compatibility wrappers.""" - -from __future__ import absolute_import - -import sys -from struct import pack - -try: - MAX_INT = sys.maxsize -except AttributeError: - MAX_INT = sys.maxint - -MAX_INT64 = (1 << 63) - 1 -MAX_INT32 = (1 << 31) - 1 -MAX_INT16 = (1 << 15) - 1 - -# Determine the word size of the processor. -if MAX_INT == MAX_INT64: - # 64-bit processor. - MACHINE_WORD_SIZE = 64 -elif MAX_INT == MAX_INT32: - # 32-bit processor. - MACHINE_WORD_SIZE = 32 -else: - # Else we just assume 64-bit processor keeping up with modern times. - MACHINE_WORD_SIZE = 64 - -try: - # < Python3 - unicode_type = unicode -except NameError: - # Python3. - unicode_type = str - -# Fake byte literals. -if str is unicode_type: - def byte_literal(s): - return s.encode('latin1') -else: - def byte_literal(s): - return s - -# ``long`` is no more. Do type detection using this instead. -try: - integer_types = (int, long) -except NameError: - integer_types = (int,) - -b = byte_literal - -# To avoid calling b() multiple times in tight loops. -ZERO_BYTE = b('\x00') -EMPTY_BYTE = b('') - - -def is_bytes(obj): - """ - Determines whether the given value is a byte string. - - :param obj: - The value to test. - :returns: - ``True`` if ``value`` is a byte string; ``False`` otherwise. - """ - return isinstance(obj, bytes) - - -def is_integer(obj): - """ - Determines whether the given value is an integer. - - :param obj: - The value to test. - :returns: - ``True`` if ``value`` is an integer; ``False`` otherwise. - """ - return isinstance(obj, integer_types) - - -def byte(num): - """ - Converts a number between 0 and 255 (both inclusive) to a base-256 (byte) - representation. - - Use it as a replacement for ``chr`` where you are expecting a byte - because this will work on all current versions of Python:: - - :param num: - An unsigned integer between 0 and 255 (both inclusive). - :returns: - A single byte. - """ - return pack("B", num) - - -def get_word_alignment(num, force_arch=64, - _machine_word_size=MACHINE_WORD_SIZE): - """ - Returns alignment details for the given number based on the platform - Python is running on. - - :param num: - Unsigned integral number. - :param force_arch: - If you don't want to use 64-bit unsigned chunks, set this to - anything other than 64. 32-bit chunks will be preferred then. - Default 64 will be used when on a 64-bit machine. - :param _machine_word_size: - (Internal) The machine word size used for alignment. - :returns: - 4-tuple:: - - (word_bits, word_bytes, - max_uint, packing_format_type) - """ - max_uint64 = 0xffffffffffffffff - max_uint32 = 0xffffffff - max_uint16 = 0xffff - max_uint8 = 0xff - - if force_arch == 64 and _machine_word_size >= 64 and num > max_uint32: - # 64-bit unsigned integer. - return 64, 8, max_uint64, "Q" - elif num > max_uint16: - # 32-bit unsigned integer - return 32, 4, max_uint32, "L" - elif num > max_uint8: - # 16-bit unsigned integer. - return 16, 2, max_uint16, "H" - else: - # 8-bit unsigned integer. - return 8, 1, max_uint8, "B" diff --git a/src/lib/rsa/_version133.py b/src/lib/rsa/_version133.py deleted file mode 100644 index ff03b45f..00000000 --- a/src/lib/rsa/_version133.py +++ /dev/null @@ -1,441 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2011 Sybren A. Stüvel -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Deprecated version of the RSA module - -.. deprecated:: 2.0 - - This submodule is deprecated and will be completely removed as of version 4.0. - -Module for calculating large primes, and RSA encryption, decryption, -signing and verification. Includes generating public and private keys. - -WARNING: this code implements the mathematics of RSA. It is not suitable for -real-world secure cryptography purposes. It has not been reviewed by a security -expert. It does not include padding of data. There are many ways in which the -output of this module, when used without any modification, can be sucessfully -attacked. -""" - -__author__ = "Sybren Stuvel, Marloes de Boer and Ivo Tamboer" -__date__ = "2010-02-05" -__version__ = '1.3.3' - -# NOTE: Python's modulo can return negative numbers. We compensate for -# this behaviour using the abs() function - -try: - import cPickle as pickle -except ImportError: - import pickle -from pickle import dumps, loads -import base64 -import math -import os -import random -import sys -import types -import zlib - -from rsa._compat import byte - -# Display a warning that this insecure version is imported. -import warnings -warnings.warn('Insecure version of the RSA module is imported as %s, be careful' - % __name__) -warnings.warn('This submodule is deprecated and will be completely removed as of version 4.0.', - DeprecationWarning) - - -def gcd(p, q): - """Returns the greatest common divisor of p and q - - - >>> gcd(42, 6) - 6 - """ - if p 0: - string = "%s%s" % (byte(number & 0xFF), string) - number /= 256 - - return string - -def fast_exponentiation(a, p, n): - """Calculates r = a^p mod n - """ - result = a % n - remainders = [] - while p != 1: - remainders.append(p & 1) - p = p >> 1 - while remainders: - rem = remainders.pop() - result = ((a ** rem) * result ** 2) % n - return result - -def read_random_int(nbits): - """Reads a random integer of approximately nbits bits rounded up - to whole bytes""" - - nbytes = ceil(nbits/8.) - randomdata = os.urandom(nbytes) - return bytes2int(randomdata) - -def ceil(x): - """ceil(x) -> int(math.ceil(x))""" - - return int(math.ceil(x)) - -def randint(minvalue, maxvalue): - """Returns a random integer x with minvalue <= x <= maxvalue""" - - # Safety - get a lot of random data even if the range is fairly - # small - min_nbits = 32 - - # The range of the random numbers we need to generate - range = maxvalue - minvalue - - # Which is this number of bytes - rangebytes = ceil(math.log(range, 2) / 8.) - - # Convert to bits, but make sure it's always at least min_nbits*2 - rangebits = max(rangebytes * 8, min_nbits * 2) - - # Take a random number of bits between min_nbits and rangebits - nbits = random.randint(min_nbits, rangebits) - - return (read_random_int(nbits) % range) + minvalue - -def fermat_little_theorem(p): - """Returns 1 if p may be prime, and something else if p definitely - is not prime""" - - a = randint(1, p-1) - return fast_exponentiation(a, p-1, p) - -def jacobi(a, b): - """Calculates the value of the Jacobi symbol (a/b) - """ - - if a % b == 0: - return 0 - result = 1 - while a > 1: - if a & 1: - if ((a-1)*(b-1) >> 2) & 1: - result = -result - b, a = a, b % a - else: - if ((b ** 2 - 1) >> 3) & 1: - result = -result - a = a >> 1 - return result - -def jacobi_witness(x, n): - """Returns False if n is an Euler pseudo-prime with base x, and - True otherwise. - """ - - j = jacobi(x, n) % n - f = fast_exponentiation(x, (n-1)/2, n) - - if j == f: return False - return True - -def randomized_primality_testing(n, k): - """Calculates whether n is composite (which is always correct) or - prime (which is incorrect with error probability 2**-k) - - Returns False if the number if composite, and True if it's - probably prime. - """ - - q = 0.5 # Property of the jacobi_witness function - - # t = int(math.ceil(k / math.log(1/q, 2))) - t = ceil(k / math.log(1/q, 2)) - for i in range(t+1): - x = randint(1, n-1) - if jacobi_witness(x, n): return False - - return True - -def is_prime(number): - """Returns True if the number is prime, and False otherwise. - """ - - """ - if not fermat_little_theorem(number) == 1: - # Not prime, according to Fermat's little theorem - return False - """ - - if randomized_primality_testing(number, 5): - # Prime, according to Jacobi - return True - - # Not prime - return False - - -def getprime(nbits): - """Returns a prime number of max. 'math.ceil(nbits/8)*8' bits. In - other words: nbits is rounded up to whole bytes. - """ - - nbytes = int(math.ceil(nbits/8.)) - - while True: - integer = read_random_int(nbits) - - # Make sure it's odd - integer |= 1 - - # Test for primeness - if is_prime(integer): break - - # Retry if not prime - - return integer - -def are_relatively_prime(a, b): - """Returns True if a and b are relatively prime, and False if they - are not. - """ - - d = gcd(a, b) - return (d == 1) - -def find_p_q(nbits): - """Returns a tuple of two different primes of nbits bits""" - - p = getprime(nbits) - while True: - q = getprime(nbits) - if not q == p: break - - return (p, q) - -def extended_euclid_gcd(a, b): - """Returns a tuple (d, i, j) such that d = gcd(a, b) = ia + jb - """ - - if b == 0: - return (a, 1, 0) - - q = abs(a % b) - r = long(a / b) - (d, k, l) = extended_euclid_gcd(b, q) - - return (d, l, k - l*r) - -# Main function: calculate encryption and decryption keys -def calculate_keys(p, q, nbits): - """Calculates an encryption and a decryption key for p and q, and - returns them as a tuple (e, d)""" - - n = p * q - phi_n = (p-1) * (q-1) - - while True: - # Make sure e has enough bits so we ensure "wrapping" through - # modulo n - e = getprime(max(8, nbits/2)) - if are_relatively_prime(e, n) and are_relatively_prime(e, phi_n): break - - (d, i, j) = extended_euclid_gcd(e, phi_n) - - if not d == 1: - raise Exception("e (%d) and phi_n (%d) are not relatively prime" % (e, phi_n)) - - if not (e * i) % phi_n == 1: - raise Exception("e (%d) and i (%d) are not mult. inv. modulo phi_n (%d)" % (e, i, phi_n)) - - return (e, i) - - -def gen_keys(nbits): - """Generate RSA keys of nbits bits. Returns (p, q, e, d). - - Note: this can take a long time, depending on the key size. - """ - - while True: - (p, q) = find_p_q(nbits) - (e, d) = calculate_keys(p, q, nbits) - - # For some reason, d is sometimes negative. We don't know how - # to fix it (yet), so we keep trying until everything is shiny - if d > 0: break - - return (p, q, e, d) - -def gen_pubpriv_keys(nbits): - """Generates public and private keys, and returns them as (pub, - priv). - - The public key consists of a dict {e: ..., , n: ....). The private - key consists of a dict {d: ...., p: ...., q: ....). - """ - - (p, q, e, d) = gen_keys(nbits) - - return ( {'e': e, 'n': p*q}, {'d': d, 'p': p, 'q': q} ) - -def encrypt_int(message, ekey, n): - """Encrypts a message using encryption key 'ekey', working modulo - n""" - - if type(message) is types.IntType: - return encrypt_int(long(message), ekey, n) - - if not type(message) is types.LongType: - raise TypeError("You must pass a long or an int") - - if message > 0 and \ - math.floor(math.log(message, 2)) > math.floor(math.log(n, 2)): - raise OverflowError("The message is too long") - - return fast_exponentiation(message, ekey, n) - -def decrypt_int(cyphertext, dkey, n): - """Decrypts a cypher text using the decryption key 'dkey', working - modulo n""" - - return encrypt_int(cyphertext, dkey, n) - -def sign_int(message, dkey, n): - """Signs 'message' using key 'dkey', working modulo n""" - - return decrypt_int(message, dkey, n) - -def verify_int(signed, ekey, n): - """verifies 'signed' using key 'ekey', working modulo n""" - - return encrypt_int(signed, ekey, n) - -def picklechops(chops): - """Pickles and base64encodes it's argument chops""" - - value = zlib.compress(dumps(chops)) - encoded = base64.encodestring(value) - return encoded.strip() - -def unpicklechops(string): - """base64decodes and unpickes it's argument string into chops""" - - return loads(zlib.decompress(base64.decodestring(string))) - -def chopstring(message, key, n, funcref): - """Splits 'message' into chops that are at most as long as n, - converts these into integers, and calls funcref(integer, key, n) - for each chop. - - Used by 'encrypt' and 'sign'. - """ - - msglen = len(message) - mbits = msglen * 8 - nbits = int(math.floor(math.log(n, 2))) - nbytes = nbits / 8 - blocks = msglen / nbytes - - if msglen % nbytes > 0: - blocks += 1 - - cypher = [] - - for bindex in range(blocks): - offset = bindex * nbytes - block = message[offset:offset+nbytes] - value = bytes2int(block) - cypher.append(funcref(value, key, n)) - - return picklechops(cypher) - -def gluechops(chops, key, n, funcref): - """Glues chops back together into a string. calls - funcref(integer, key, n) for each chop. - - Used by 'decrypt' and 'verify'. - """ - message = "" - - chops = unpicklechops(chops) - - for cpart in chops: - mpart = funcref(cpart, key, n) - message += int2bytes(mpart) - - return message - -def encrypt(message, key): - """Encrypts a string 'message' with the public key 'key'""" - - return chopstring(message, key['e'], key['n'], encrypt_int) - -def sign(message, key): - """Signs a string 'message' with the private key 'key'""" - - return chopstring(message, key['d'], key['p']*key['q'], decrypt_int) - -def decrypt(cypher, key): - """Decrypts a cypher with the private key 'key'""" - - return gluechops(cypher, key['d'], key['p']*key['q'], decrypt_int) - -def verify(cypher, key): - """Verifies a cypher with the public key 'key'""" - - return gluechops(cypher, key['e'], key['n'], encrypt_int) - -# Do doctest if we're not imported -if __name__ == "__main__": - import doctest - doctest.testmod() - -__all__ = ["gen_pubpriv_keys", "encrypt", "decrypt", "sign", "verify"] - diff --git a/src/lib/rsa/_version200.py b/src/lib/rsa/_version200.py deleted file mode 100644 index 1a169494..00000000 --- a/src/lib/rsa/_version200.py +++ /dev/null @@ -1,513 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2011 Sybren A. Stüvel -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Deprecated version of the RSA module - -.. deprecated:: 3.0 - - This submodule is deprecated and will be completely removed as of version 4.0. - -""" - -__author__ = "Sybren Stuvel, Marloes de Boer, Ivo Tamboer, and Barry Mead" -__date__ = "2010-02-08" -__version__ = '2.0' - -import math -import os -import random -import sys -import types -from rsa._compat import byte - -# Display a warning that this insecure version is imported. -import warnings -warnings.warn('Insecure version of the RSA module is imported as %s' % __name__) -warnings.warn('This submodule is deprecated and will be completely removed as of version 4.0.', - DeprecationWarning) - - -def bit_size(number): - """Returns the number of bits required to hold a specific long number""" - - return int(math.ceil(math.log(number,2))) - -def gcd(p, q): - """Returns the greatest common divisor of p and q - >>> gcd(48, 180) - 12 - """ - # Iterateive Version is faster and uses much less stack space - while q != 0: - if p < q: (p,q) = (q,p) - (p,q) = (q, p % q) - return p - - -def bytes2int(bytes): - r"""Converts a list of bytes or a string to an integer - """ - - if not (type(bytes) is types.ListType or type(bytes) is types.StringType): - raise TypeError("You must pass a string or a list") - - # Convert byte stream to integer - integer = 0 - for byte in bytes: - integer *= 256 - if type(byte) is types.StringType: byte = ord(byte) - integer += byte - - return integer - -def int2bytes(number): - """ - Converts a number to a string of bytes - """ - - if not (type(number) is types.LongType or type(number) is types.IntType): - raise TypeError("You must pass a long or an int") - - string = "" - - while number > 0: - string = "%s%s" % (byte(number & 0xFF), string) - number /= 256 - - return string - -def to64(number): - """Converts a number in the range of 0 to 63 into base 64 digit - character in the range of '0'-'9', 'A'-'Z', 'a'-'z','-','_'. - """ - - if not (type(number) is types.LongType or type(number) is types.IntType): - raise TypeError("You must pass a long or an int") - - if 0 <= number <= 9: #00-09 translates to '0' - '9' - return byte(number + 48) - - if 10 <= number <= 35: - return byte(number + 55) #10-35 translates to 'A' - 'Z' - - if 36 <= number <= 61: - return byte(number + 61) #36-61 translates to 'a' - 'z' - - if number == 62: # 62 translates to '-' (minus) - return byte(45) - - if number == 63: # 63 translates to '_' (underscore) - return byte(95) - - raise ValueError('Invalid Base64 value: %i' % number) - - -def from64(number): - """Converts an ordinal character value in the range of - 0-9,A-Z,a-z,-,_ to a number in the range of 0-63. - """ - - if not (type(number) is types.LongType or type(number) is types.IntType): - raise TypeError("You must pass a long or an int") - - if 48 <= number <= 57: #ord('0') - ord('9') translates to 0-9 - return(number - 48) - - if 65 <= number <= 90: #ord('A') - ord('Z') translates to 10-35 - return(number - 55) - - if 97 <= number <= 122: #ord('a') - ord('z') translates to 36-61 - return(number - 61) - - if number == 45: #ord('-') translates to 62 - return(62) - - if number == 95: #ord('_') translates to 63 - return(63) - - raise ValueError('Invalid Base64 value: %i' % number) - - -def int2str64(number): - """Converts a number to a string of base64 encoded characters in - the range of '0'-'9','A'-'Z,'a'-'z','-','_'. - """ - - if not (type(number) is types.LongType or type(number) is types.IntType): - raise TypeError("You must pass a long or an int") - - string = "" - - while number > 0: - string = "%s%s" % (to64(number & 0x3F), string) - number /= 64 - - return string - - -def str642int(string): - """Converts a base64 encoded string into an integer. - The chars of this string in in the range '0'-'9','A'-'Z','a'-'z','-','_' - """ - - if not (type(string) is types.ListType or type(string) is types.StringType): - raise TypeError("You must pass a string or a list") - - integer = 0 - for byte in string: - integer *= 64 - if type(byte) is types.StringType: byte = ord(byte) - integer += from64(byte) - - return integer - -def read_random_int(nbits): - """Reads a random integer of approximately nbits bits rounded up - to whole bytes""" - - nbytes = int(math.ceil(nbits/8.)) - randomdata = os.urandom(nbytes) - return bytes2int(randomdata) - -def randint(minvalue, maxvalue): - """Returns a random integer x with minvalue <= x <= maxvalue""" - - # Safety - get a lot of random data even if the range is fairly - # small - min_nbits = 32 - - # The range of the random numbers we need to generate - range = (maxvalue - minvalue) + 1 - - # Which is this number of bytes - rangebytes = ((bit_size(range) + 7) / 8) - - # Convert to bits, but make sure it's always at least min_nbits*2 - rangebits = max(rangebytes * 8, min_nbits * 2) - - # Take a random number of bits between min_nbits and rangebits - nbits = random.randint(min_nbits, rangebits) - - return (read_random_int(nbits) % range) + minvalue - -def jacobi(a, b): - """Calculates the value of the Jacobi symbol (a/b) - where both a and b are positive integers, and b is odd - """ - - if a == 0: return 0 - result = 1 - while a > 1: - if a & 1: - if ((a-1)*(b-1) >> 2) & 1: - result = -result - a, b = b % a, a - else: - if (((b * b) - 1) >> 3) & 1: - result = -result - a >>= 1 - if a == 0: return 0 - return result - -def jacobi_witness(x, n): - """Returns False if n is an Euler pseudo-prime with base x, and - True otherwise. - """ - - j = jacobi(x, n) % n - f = pow(x, (n-1)/2, n) - - if j == f: return False - return True - -def randomized_primality_testing(n, k): - """Calculates whether n is composite (which is always correct) or - prime (which is incorrect with error probability 2**-k) - - Returns False if the number is composite, and True if it's - probably prime. - """ - - # 50% of Jacobi-witnesses can report compositness of non-prime numbers - - for i in range(k): - x = randint(1, n-1) - if jacobi_witness(x, n): return False - - return True - -def is_prime(number): - """Returns True if the number is prime, and False otherwise. - """ - - if randomized_primality_testing(number, 6): - # Prime, according to Jacobi - return True - - # Not prime - return False - - -def getprime(nbits): - """Returns a prime number of max. 'math.ceil(nbits/8)*8' bits. In - other words: nbits is rounded up to whole bytes. - """ - - while True: - integer = read_random_int(nbits) - - # Make sure it's odd - integer |= 1 - - # Test for primeness - if is_prime(integer): break - - # Retry if not prime - - return integer - -def are_relatively_prime(a, b): - """Returns True if a and b are relatively prime, and False if they - are not. - - >>> are_relatively_prime(2, 3) - 1 - >>> are_relatively_prime(2, 4) - 0 - """ - - d = gcd(a, b) - return (d == 1) - -def find_p_q(nbits): - """Returns a tuple of two different primes of nbits bits""" - pbits = nbits + (nbits/16) #Make sure that p and q aren't too close - qbits = nbits - (nbits/16) #or the factoring programs can factor n - p = getprime(pbits) - while True: - q = getprime(qbits) - #Make sure p and q are different. - if not q == p: break - return (p, q) - -def extended_gcd(a, b): - """Returns a tuple (r, i, j) such that r = gcd(a, b) = ia + jb - """ - # r = gcd(a,b) i = multiplicitive inverse of a mod b - # or j = multiplicitive inverse of b mod a - # Neg return values for i or j are made positive mod b or a respectively - # Iterateive Version is faster and uses much less stack space - x = 0 - y = 1 - lx = 1 - ly = 0 - oa = a #Remember original a/b to remove - ob = b #negative values from return results - while b != 0: - q = long(a/b) - (a, b) = (b, a % b) - (x, lx) = ((lx - (q * x)),x) - (y, ly) = ((ly - (q * y)),y) - if (lx < 0): lx += ob #If neg wrap modulo orignal b - if (ly < 0): ly += oa #If neg wrap modulo orignal a - return (a, lx, ly) #Return only positive values - -# Main function: calculate encryption and decryption keys -def calculate_keys(p, q, nbits): - """Calculates an encryption and a decryption key for p and q, and - returns them as a tuple (e, d)""" - - n = p * q - phi_n = (p-1) * (q-1) - - while True: - # Make sure e has enough bits so we ensure "wrapping" through - # modulo n - e = max(65537,getprime(nbits/4)) - if are_relatively_prime(e, n) and are_relatively_prime(e, phi_n): break - - (d, i, j) = extended_gcd(e, phi_n) - - if not d == 1: - raise Exception("e (%d) and phi_n (%d) are not relatively prime" % (e, phi_n)) - if (i < 0): - raise Exception("New extended_gcd shouldn't return negative values") - if not (e * i) % phi_n == 1: - raise Exception("e (%d) and i (%d) are not mult. inv. modulo phi_n (%d)" % (e, i, phi_n)) - - return (e, i) - - -def gen_keys(nbits): - """Generate RSA keys of nbits bits. Returns (p, q, e, d). - - Note: this can take a long time, depending on the key size. - """ - - (p, q) = find_p_q(nbits) - (e, d) = calculate_keys(p, q, nbits) - - return (p, q, e, d) - -def newkeys(nbits): - """Generates public and private keys, and returns them as (pub, - priv). - - The public key consists of a dict {e: ..., , n: ....). The private - key consists of a dict {d: ...., p: ...., q: ....). - """ - nbits = max(9,nbits) # Don't let nbits go below 9 bits - (p, q, e, d) = gen_keys(nbits) - - return ( {'e': e, 'n': p*q}, {'d': d, 'p': p, 'q': q} ) - -def encrypt_int(message, ekey, n): - """Encrypts a message using encryption key 'ekey', working modulo n""" - - if type(message) is types.IntType: - message = long(message) - - if not type(message) is types.LongType: - raise TypeError("You must pass a long or int") - - if message < 0 or message > n: - raise OverflowError("The message is too long") - - #Note: Bit exponents start at zero (bit counts start at 1) this is correct - safebit = bit_size(n) - 2 #compute safe bit (MSB - 1) - message += (1 << safebit) #add safebit to ensure folding - - return pow(message, ekey, n) - -def decrypt_int(cyphertext, dkey, n): - """Decrypts a cypher text using the decryption key 'dkey', working - modulo n""" - - message = pow(cyphertext, dkey, n) - - safebit = bit_size(n) - 2 #compute safe bit (MSB - 1) - message -= (1 << safebit) #remove safebit before decode - - return message - -def encode64chops(chops): - """base64encodes chops and combines them into a ',' delimited string""" - - chips = [] #chips are character chops - - for value in chops: - chips.append(int2str64(value)) - - #delimit chops with comma - encoded = ','.join(chips) - - return encoded - -def decode64chops(string): - """base64decodes and makes a ',' delimited string into chops""" - - chips = string.split(',') #split chops at commas - - chops = [] - - for string in chips: #make char chops (chips) into chops - chops.append(str642int(string)) - - return chops - -def chopstring(message, key, n, funcref): - """Chops the 'message' into integers that fit into n, - leaving room for a safebit to be added to ensure that all - messages fold during exponentiation. The MSB of the number n - is not independant modulo n (setting it could cause overflow), so - use the next lower bit for the safebit. Therefore reserve 2-bits - in the number n for non-data bits. Calls specified encryption - function for each chop. - - Used by 'encrypt' and 'sign'. - """ - - msglen = len(message) - mbits = msglen * 8 - #Set aside 2-bits so setting of safebit won't overflow modulo n. - nbits = bit_size(n) - 2 # leave room for safebit - nbytes = nbits / 8 - blocks = msglen / nbytes - - if msglen % nbytes > 0: - blocks += 1 - - cypher = [] - - for bindex in range(blocks): - offset = bindex * nbytes - block = message[offset:offset+nbytes] - value = bytes2int(block) - cypher.append(funcref(value, key, n)) - - return encode64chops(cypher) #Encode encrypted ints to base64 strings - -def gluechops(string, key, n, funcref): - """Glues chops back together into a string. calls - funcref(integer, key, n) for each chop. - - Used by 'decrypt' and 'verify'. - """ - message = "" - - chops = decode64chops(string) #Decode base64 strings into integer chops - - for cpart in chops: - mpart = funcref(cpart, key, n) #Decrypt each chop - message += int2bytes(mpart) #Combine decrypted strings into a msg - - return message - -def encrypt(message, key): - """Encrypts a string 'message' with the public key 'key'""" - if 'n' not in key: - raise Exception("You must use the public key with encrypt") - - return chopstring(message, key['e'], key['n'], encrypt_int) - -def sign(message, key): - """Signs a string 'message' with the private key 'key'""" - if 'p' not in key: - raise Exception("You must use the private key with sign") - - return chopstring(message, key['d'], key['p']*key['q'], encrypt_int) - -def decrypt(cypher, key): - """Decrypts a string 'cypher' with the private key 'key'""" - if 'p' not in key: - raise Exception("You must use the private key with decrypt") - - return gluechops(cypher, key['d'], key['p']*key['q'], decrypt_int) - -def verify(cypher, key): - """Verifies a string 'cypher' with the public key 'key'""" - if 'n' not in key: - raise Exception("You must use the public key with verify") - - return gluechops(cypher, key['e'], key['n'], decrypt_int) - -# Do doctest if we're not imported -if __name__ == "__main__": - import doctest - doctest.testmod() - -__all__ = ["newkeys", "encrypt", "decrypt", "sign", "verify"] - diff --git a/src/lib/rsa/asn1.py b/src/lib/rsa/asn1.py deleted file mode 100644 index b724b8f5..00000000 --- a/src/lib/rsa/asn1.py +++ /dev/null @@ -1,53 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2011 Sybren A. Stüvel -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""ASN.1 definitions. - -Not all ASN.1-handling code use these definitions, but when it does, they should be here. -""" - -from pyasn1.type import univ, namedtype, tag - - -class PubKeyHeader(univ.Sequence): - componentType = namedtype.NamedTypes( - namedtype.NamedType('oid', univ.ObjectIdentifier()), - namedtype.NamedType('parameters', univ.Null()), - ) - - -class OpenSSLPubKey(univ.Sequence): - componentType = namedtype.NamedTypes( - namedtype.NamedType('header', PubKeyHeader()), - - # This little hack (the implicit tag) allows us to get a Bit String as Octet String - namedtype.NamedType('key', univ.OctetString().subtype( - implicitTag=tag.Tag(tagClass=0, tagFormat=0, tagId=3))), - ) - - -class AsnPubKey(univ.Sequence): - """ASN.1 contents of DER encoded public key: - - RSAPublicKey ::= SEQUENCE { - modulus INTEGER, -- n - publicExponent INTEGER, -- e - """ - - componentType = namedtype.NamedTypes( - namedtype.NamedType('modulus', univ.Integer()), - namedtype.NamedType('publicExponent', univ.Integer()), - ) diff --git a/src/lib/rsa/bigfile.py b/src/lib/rsa/bigfile.py deleted file mode 100644 index 3a09716a..00000000 --- a/src/lib/rsa/bigfile.py +++ /dev/null @@ -1,135 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2011 Sybren A. Stüvel -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Large file support - -.. deprecated:: 3.4 - - The VARBLOCK format is NOT recommended for general use, has been deprecated since - Python-RSA 3.4, and will be removed in a future release. It's vulnerable to a - number of attacks: - - 1. decrypt/encrypt_bigfile() does not implement `Authenticated encryption`_ nor - uses MACs to verify messages before decrypting public key encrypted messages. - - 2. decrypt/encrypt_bigfile() does not use hybrid encryption (it uses plain RSA) - and has no method for chaining, so block reordering is possible. - - See `issue #19 on Github`_ for more information. - -.. _Authenticated encryption: https://en.wikipedia.org/wiki/Authenticated_encryption -.. _issue #19 on Github: https://github.com/sybrenstuvel/python-rsa/issues/13 - - -This module contains functions to: - - - break a file into smaller blocks, and encrypt them, and store the - encrypted blocks in another file. - - - take such an encrypted files, decrypt its blocks, and reconstruct the - original file. - -The encrypted file format is as follows, where || denotes byte concatenation: - - FILE := VERSION || BLOCK || BLOCK ... - - BLOCK := LENGTH || DATA - - LENGTH := varint-encoded length of the subsequent data. Varint comes from - Google Protobuf, and encodes an integer into a variable number of bytes. - Each byte uses the 7 lowest bits to encode the value. The highest bit set - to 1 indicates the next byte is also part of the varint. The last byte will - have this bit set to 0. - -This file format is called the VARBLOCK format, in line with the varint format -used to denote the block sizes. - -""" - -import warnings - -from rsa import key, common, pkcs1, varblock -from rsa._compat import byte - - -def encrypt_bigfile(infile, outfile, pub_key): - """Encrypts a file, writing it to 'outfile' in VARBLOCK format. - - .. deprecated:: 3.4 - This function was deprecated in Python-RSA version 3.4 due to security issues - in the VARBLOCK format. See the documentation_ for more information. - - .. _documentation: https://stuvel.eu/python-rsa-doc/usage.html#working-with-big-files - - :param infile: file-like object to read the cleartext from - :param outfile: file-like object to write the crypto in VARBLOCK format to - :param pub_key: :py:class:`rsa.PublicKey` to encrypt with - - """ - - warnings.warn("The 'rsa.bigfile.encrypt_bigfile' function was deprecated in Python-RSA version " - "3.4 due to security issues in the VARBLOCK format. See " - "https://stuvel.eu/python-rsa-doc/usage.html#working-with-big-files " - "for more information.", - DeprecationWarning, stacklevel=2) - - if not isinstance(pub_key, key.PublicKey): - raise TypeError('Public key required, but got %r' % pub_key) - - key_bytes = common.bit_size(pub_key.n) // 8 - blocksize = key_bytes - 11 # keep space for PKCS#1 padding - - # Write the version number to the VARBLOCK file - outfile.write(byte(varblock.VARBLOCK_VERSION)) - - # Encrypt and write each block - for block in varblock.yield_fixedblocks(infile, blocksize): - crypto = pkcs1.encrypt(block, pub_key) - - varblock.write_varint(outfile, len(crypto)) - outfile.write(crypto) - - -def decrypt_bigfile(infile, outfile, priv_key): - """Decrypts an encrypted VARBLOCK file, writing it to 'outfile' - - .. deprecated:: 3.4 - This function was deprecated in Python-RSA version 3.4 due to security issues - in the VARBLOCK format. See the documentation_ for more information. - - .. _documentation: https://stuvel.eu/python-rsa-doc/usage.html#working-with-big-files - - :param infile: file-like object to read the crypto in VARBLOCK format from - :param outfile: file-like object to write the cleartext to - :param priv_key: :py:class:`rsa.PrivateKey` to decrypt with - - """ - - warnings.warn("The 'rsa.bigfile.decrypt_bigfile' function was deprecated in Python-RSA version " - "3.4 due to security issues in the VARBLOCK format. See " - "https://stuvel.eu/python-rsa-doc/usage.html#working-with-big-files " - "for more information.", - DeprecationWarning, stacklevel=2) - - if not isinstance(priv_key, key.PrivateKey): - raise TypeError('Private key required, but got %r' % priv_key) - - for block in varblock.yield_varblocks(infile): - cleartext = pkcs1.decrypt(block, priv_key) - outfile.write(cleartext) - - -__all__ = ['encrypt_bigfile', 'decrypt_bigfile'] diff --git a/src/lib/rsa/cli.py b/src/lib/rsa/cli.py deleted file mode 100644 index 3a218782..00000000 --- a/src/lib/rsa/cli.py +++ /dev/null @@ -1,383 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2011 Sybren A. Stüvel -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Commandline scripts. - -These scripts are called by the executables defined in setup.py. -""" - -from __future__ import with_statement, print_function - -import abc -import sys -from optparse import OptionParser - -import rsa -import rsa.bigfile -import rsa.pkcs1 - -HASH_METHODS = sorted(rsa.pkcs1.HASH_METHODS.keys()) - - -def keygen(): - """Key generator.""" - - # Parse the CLI options - parser = OptionParser(usage='usage: %prog [options] keysize', - description='Generates a new RSA keypair of "keysize" bits.') - - parser.add_option('--pubout', type='string', - help='Output filename for the public key. The public key is ' - 'not saved if this option is not present. You can use ' - 'pyrsa-priv2pub to create the public key file later.') - - parser.add_option('-o', '--out', type='string', - help='Output filename for the private key. The key is ' - 'written to stdout if this option is not present.') - - parser.add_option('--form', - help='key format of the private and public keys - default PEM', - choices=('PEM', 'DER'), default='PEM') - - (cli, cli_args) = parser.parse_args(sys.argv[1:]) - - if len(cli_args) != 1: - parser.print_help() - raise SystemExit(1) - - try: - keysize = int(cli_args[0]) - except ValueError: - parser.print_help() - print('Not a valid number: %s' % cli_args[0], file=sys.stderr) - raise SystemExit(1) - - print('Generating %i-bit key' % keysize, file=sys.stderr) - (pub_key, priv_key) = rsa.newkeys(keysize) - - # Save public key - if cli.pubout: - print('Writing public key to %s' % cli.pubout, file=sys.stderr) - data = pub_key.save_pkcs1(format=cli.form) - with open(cli.pubout, 'wb') as outfile: - outfile.write(data) - - # Save private key - data = priv_key.save_pkcs1(format=cli.form) - - if cli.out: - print('Writing private key to %s' % cli.out, file=sys.stderr) - with open(cli.out, 'wb') as outfile: - outfile.write(data) - else: - print('Writing private key to stdout', file=sys.stderr) - sys.stdout.write(data) - - -class CryptoOperation(object): - """CLI callable that operates with input, output, and a key.""" - - __metaclass__ = abc.ABCMeta - - keyname = 'public' # or 'private' - usage = 'usage: %%prog [options] %(keyname)s_key' - description = None - operation = 'decrypt' - operation_past = 'decrypted' - operation_progressive = 'decrypting' - input_help = 'Name of the file to %(operation)s. Reads from stdin if ' \ - 'not specified.' - output_help = 'Name of the file to write the %(operation_past)s file ' \ - 'to. Written to stdout if this option is not present.' - expected_cli_args = 1 - has_output = True - - key_class = rsa.PublicKey - - def __init__(self): - self.usage = self.usage % self.__class__.__dict__ - self.input_help = self.input_help % self.__class__.__dict__ - self.output_help = self.output_help % self.__class__.__dict__ - - @abc.abstractmethod - def perform_operation(self, indata, key, cli_args=None): - """Performs the program's operation. - - Implement in a subclass. - - :returns: the data to write to the output. - """ - - def __call__(self): - """Runs the program.""" - - (cli, cli_args) = self.parse_cli() - - key = self.read_key(cli_args[0], cli.keyform) - - indata = self.read_infile(cli.input) - - print(self.operation_progressive.title(), file=sys.stderr) - outdata = self.perform_operation(indata, key, cli_args) - - if self.has_output: - self.write_outfile(outdata, cli.output) - - def parse_cli(self): - """Parse the CLI options - - :returns: (cli_opts, cli_args) - """ - - parser = OptionParser(usage=self.usage, description=self.description) - - parser.add_option('-i', '--input', type='string', help=self.input_help) - - if self.has_output: - parser.add_option('-o', '--output', type='string', help=self.output_help) - - parser.add_option('--keyform', - help='Key format of the %s key - default PEM' % self.keyname, - choices=('PEM', 'DER'), default='PEM') - - (cli, cli_args) = parser.parse_args(sys.argv[1:]) - - if len(cli_args) != self.expected_cli_args: - parser.print_help() - raise SystemExit(1) - - return cli, cli_args - - def read_key(self, filename, keyform): - """Reads a public or private key.""" - - print('Reading %s key from %s' % (self.keyname, filename), file=sys.stderr) - with open(filename, 'rb') as keyfile: - keydata = keyfile.read() - - return self.key_class.load_pkcs1(keydata, keyform) - - def read_infile(self, inname): - """Read the input file""" - - if inname: - print('Reading input from %s' % inname, file=sys.stderr) - with open(inname, 'rb') as infile: - return infile.read() - - print('Reading input from stdin', file=sys.stderr) - return sys.stdin.read() - - def write_outfile(self, outdata, outname): - """Write the output file""" - - if outname: - print('Writing output to %s' % outname, file=sys.stderr) - with open(outname, 'wb') as outfile: - outfile.write(outdata) - else: - print('Writing output to stdout', file=sys.stderr) - sys.stdout.write(outdata) - - -class EncryptOperation(CryptoOperation): - """Encrypts a file.""" - - keyname = 'public' - description = ('Encrypts a file. The file must be shorter than the key ' - 'length in order to be encrypted. For larger files, use the ' - 'pyrsa-encrypt-bigfile command.') - operation = 'encrypt' - operation_past = 'encrypted' - operation_progressive = 'encrypting' - - def perform_operation(self, indata, pub_key, cli_args=None): - """Encrypts files.""" - - return rsa.encrypt(indata, pub_key) - - -class DecryptOperation(CryptoOperation): - """Decrypts a file.""" - - keyname = 'private' - description = ('Decrypts a file. The original file must be shorter than ' - 'the key length in order to have been encrypted. For larger ' - 'files, use the pyrsa-decrypt-bigfile command.') - operation = 'decrypt' - operation_past = 'decrypted' - operation_progressive = 'decrypting' - key_class = rsa.PrivateKey - - def perform_operation(self, indata, priv_key, cli_args=None): - """Decrypts files.""" - - return rsa.decrypt(indata, priv_key) - - -class SignOperation(CryptoOperation): - """Signs a file.""" - - keyname = 'private' - usage = 'usage: %%prog [options] private_key hash_method' - description = ('Signs a file, outputs the signature. Choose the hash ' - 'method from %s' % ', '.join(HASH_METHODS)) - operation = 'sign' - operation_past = 'signature' - operation_progressive = 'Signing' - key_class = rsa.PrivateKey - expected_cli_args = 2 - - output_help = ('Name of the file to write the signature to. Written ' - 'to stdout if this option is not present.') - - def perform_operation(self, indata, priv_key, cli_args): - """Signs files.""" - - hash_method = cli_args[1] - if hash_method not in HASH_METHODS: - raise SystemExit('Invalid hash method, choose one of %s' % - ', '.join(HASH_METHODS)) - - return rsa.sign(indata, priv_key, hash_method) - - -class VerifyOperation(CryptoOperation): - """Verify a signature.""" - - keyname = 'public' - usage = 'usage: %%prog [options] public_key signature_file' - description = ('Verifies a signature, exits with status 0 upon success, ' - 'prints an error message and exits with status 1 upon error.') - operation = 'verify' - operation_past = 'verified' - operation_progressive = 'Verifying' - key_class = rsa.PublicKey - expected_cli_args = 2 - has_output = False - - def perform_operation(self, indata, pub_key, cli_args): - """Verifies files.""" - - signature_file = cli_args[1] - - with open(signature_file, 'rb') as sigfile: - signature = sigfile.read() - - try: - rsa.verify(indata, signature, pub_key) - except rsa.VerificationError: - raise SystemExit('Verification failed.') - - print('Verification OK', file=sys.stderr) - - -class BigfileOperation(CryptoOperation): - """CryptoOperation that doesn't read the entire file into memory.""" - - def __init__(self): - CryptoOperation.__init__(self) - - self.file_objects = [] - - def __del__(self): - """Closes any open file handles.""" - - for fobj in self.file_objects: - fobj.close() - - def __call__(self): - """Runs the program.""" - - (cli, cli_args) = self.parse_cli() - - key = self.read_key(cli_args[0], cli.keyform) - - # Get the file handles - infile = self.get_infile(cli.input) - outfile = self.get_outfile(cli.output) - - # Call the operation - print(self.operation_progressive.title(), file=sys.stderr) - self.perform_operation(infile, outfile, key, cli_args) - - def get_infile(self, inname): - """Returns the input file object""" - - if inname: - print('Reading input from %s' % inname, file=sys.stderr) - fobj = open(inname, 'rb') - self.file_objects.append(fobj) - else: - print('Reading input from stdin', file=sys.stderr) - fobj = sys.stdin - - return fobj - - def get_outfile(self, outname): - """Returns the output file object""" - - if outname: - print('Will write output to %s' % outname, file=sys.stderr) - fobj = open(outname, 'wb') - self.file_objects.append(fobj) - else: - print('Will write output to stdout', file=sys.stderr) - fobj = sys.stdout - - return fobj - - -class EncryptBigfileOperation(BigfileOperation): - """Encrypts a file to VARBLOCK format.""" - - keyname = 'public' - description = ('Encrypts a file to an encrypted VARBLOCK file. The file ' - 'can be larger than the key length, but the output file is only ' - 'compatible with Python-RSA.') - operation = 'encrypt' - operation_past = 'encrypted' - operation_progressive = 'encrypting' - - def perform_operation(self, infile, outfile, pub_key, cli_args=None): - """Encrypts files to VARBLOCK.""" - - return rsa.bigfile.encrypt_bigfile(infile, outfile, pub_key) - - -class DecryptBigfileOperation(BigfileOperation): - """Decrypts a file in VARBLOCK format.""" - - keyname = 'private' - description = ('Decrypts an encrypted VARBLOCK file that was encrypted ' - 'with pyrsa-encrypt-bigfile') - operation = 'decrypt' - operation_past = 'decrypted' - operation_progressive = 'decrypting' - key_class = rsa.PrivateKey - - def perform_operation(self, infile, outfile, priv_key, cli_args=None): - """Decrypts a VARBLOCK file.""" - - return rsa.bigfile.decrypt_bigfile(infile, outfile, priv_key) - - -encrypt = EncryptOperation() -decrypt = DecryptOperation() -sign = SignOperation() -verify = VerifyOperation() -encrypt_bigfile = EncryptBigfileOperation() -decrypt_bigfile = DecryptBigfileOperation() diff --git a/src/lib/rsa/common.py b/src/lib/rsa/common.py deleted file mode 100644 index e0743340..00000000 --- a/src/lib/rsa/common.py +++ /dev/null @@ -1,188 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2011 Sybren A. Stüvel -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Common functionality shared by several modules.""" - - -def bit_size(num): - """ - Number of bits needed to represent a integer excluding any prefix - 0 bits. - - As per definition from https://wiki.python.org/moin/BitManipulation and - to match the behavior of the Python 3 API. - - Usage:: - - >>> bit_size(1023) - 10 - >>> bit_size(1024) - 11 - >>> bit_size(1025) - 11 - - :param num: - Integer value. If num is 0, returns 0. Only the absolute value of the - number is considered. Therefore, signed integers will be abs(num) - before the number's bit length is determined. - :returns: - Returns the number of bits in the integer. - """ - if num == 0: - return 0 - if num < 0: - num = -num - - # Make sure this is an int and not a float. - num & 1 - - hex_num = "%x" % num - return ((len(hex_num) - 1) * 4) + { - '0': 0, '1': 1, '2': 2, '3': 2, - '4': 3, '5': 3, '6': 3, '7': 3, - '8': 4, '9': 4, 'a': 4, 'b': 4, - 'c': 4, 'd': 4, 'e': 4, 'f': 4, - }[hex_num[0]] - - -def _bit_size(number): - """ - Returns the number of bits required to hold a specific long number. - """ - if number < 0: - raise ValueError('Only nonnegative numbers possible: %s' % number) - - if number == 0: - return 0 - - # This works, even with very large numbers. When using math.log(number, 2), - # you'll get rounding errors and it'll fail. - bits = 0 - while number: - bits += 1 - number >>= 1 - - return bits - - -def byte_size(number): - """ - Returns the number of bytes required to hold a specific long number. - - The number of bytes is rounded up. - - Usage:: - - >>> byte_size(1 << 1023) - 128 - >>> byte_size((1 << 1024) - 1) - 128 - >>> byte_size(1 << 1024) - 129 - - :param number: - An unsigned integer - :returns: - The number of bytes required to hold a specific long number. - """ - quanta, mod = divmod(bit_size(number), 8) - if mod or number == 0: - quanta += 1 - return quanta - # return int(math.ceil(bit_size(number) / 8.0)) - - -def extended_gcd(a, b): - """Returns a tuple (r, i, j) such that r = gcd(a, b) = ia + jb - """ - # r = gcd(a,b) i = multiplicitive inverse of a mod b - # or j = multiplicitive inverse of b mod a - # Neg return values for i or j are made positive mod b or a respectively - # Iterateive Version is faster and uses much less stack space - x = 0 - y = 1 - lx = 1 - ly = 0 - oa = a # Remember original a/b to remove - ob = b # negative values from return results - while b != 0: - q = a // b - (a, b) = (b, a % b) - (x, lx) = ((lx - (q * x)), x) - (y, ly) = ((ly - (q * y)), y) - if lx < 0: - lx += ob # If neg wrap modulo orignal b - if ly < 0: - ly += oa # If neg wrap modulo orignal a - return a, lx, ly # Return only positive values - - -def inverse(x, n): - """Returns x^-1 (mod n) - - >>> inverse(7, 4) - 3 - >>> (inverse(143, 4) * 143) % 4 - 1 - """ - - (divider, inv, _) = extended_gcd(x, n) - - if divider != 1: - raise ValueError("x (%d) and n (%d) are not relatively prime" % (x, n)) - - return inv - - -def crt(a_values, modulo_values): - """Chinese Remainder Theorem. - - Calculates x such that x = a[i] (mod m[i]) for each i. - - :param a_values: the a-values of the above equation - :param modulo_values: the m-values of the above equation - :returns: x such that x = a[i] (mod m[i]) for each i - - - >>> crt([2, 3], [3, 5]) - 8 - - >>> crt([2, 3, 2], [3, 5, 7]) - 23 - - >>> crt([2, 3, 0], [7, 11, 15]) - 135 - """ - - m = 1 - x = 0 - - for modulo in modulo_values: - m *= modulo - - for (m_i, a_i) in zip(modulo_values, a_values): - M_i = m // m_i - inv = inverse(M_i, m_i) - - x = (x + a_i * M_i * inv) % m - - return x - - -if __name__ == '__main__': - import doctest - - doctest.testmod() diff --git a/src/lib/rsa/core.py b/src/lib/rsa/core.py deleted file mode 100644 index b3114d9e..00000000 --- a/src/lib/rsa/core.py +++ /dev/null @@ -1,57 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2011 Sybren A. Stüvel -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Core mathematical operations. - -This is the actual core RSA implementation, which is only defined -mathematically on integers. -""" - -from rsa._compat import is_integer - - -def assert_int(var, name): - if is_integer(var): - return - - raise TypeError('%s should be an integer, not %s' % (name, var.__class__)) - - -def encrypt_int(message, ekey, n): - """Encrypts a message using encryption key 'ekey', working modulo n""" - - assert_int(message, 'message') - assert_int(ekey, 'ekey') - assert_int(n, 'n') - - if message < 0: - raise ValueError('Only non-negative numbers are supported') - - if message > n: - raise OverflowError("The message %i is too long for n=%i" % (message, n)) - - return pow(message, ekey, n) - - -def decrypt_int(cyphertext, dkey, n): - """Decrypts a cypher text using the decryption key 'dkey', working modulo n""" - - assert_int(cyphertext, 'cyphertext') - assert_int(dkey, 'dkey') - assert_int(n, 'n') - - message = pow(cyphertext, dkey, n) - return message diff --git a/src/lib/rsa/key.py b/src/lib/rsa/key.py deleted file mode 100644 index 64600a27..00000000 --- a/src/lib/rsa/key.py +++ /dev/null @@ -1,739 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2011 Sybren A. Stüvel -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""RSA key generation code. - -Create new keys with the newkeys() function. It will give you a PublicKey and a -PrivateKey object. - -Loading and saving keys requires the pyasn1 module. This module is imported as -late as possible, such that other functionality will remain working in absence -of pyasn1. - -.. note:: - - Storing public and private keys via the `pickle` module is possible. - However, it is insecure to load a key from an untrusted source. - The pickle module is not secure against erroneous or maliciously - constructed data. Never unpickle data received from an untrusted - or unauthenticated source. - -""" - -import logging -from rsa._compat import b - -import rsa.prime -import rsa.pem -import rsa.common -import rsa.randnum -import rsa.core - -log = logging.getLogger(__name__) -DEFAULT_EXPONENT = 65537 - - -class AbstractKey(object): - """Abstract superclass for private and public keys.""" - - __slots__ = ('n', 'e') - - def __init__(self, n, e): - self.n = n - self.e = e - - @classmethod - def load_pkcs1(cls, keyfile, format='PEM'): - """Loads a key in PKCS#1 DER or PEM format. - - :param keyfile: contents of a DER- or PEM-encoded file that contains - the public key. - :param format: the format of the file to load; 'PEM' or 'DER' - - :return: a PublicKey object - """ - - methods = { - 'PEM': cls._load_pkcs1_pem, - 'DER': cls._load_pkcs1_der, - } - - method = cls._assert_format_exists(format, methods) - return method(keyfile) - - @staticmethod - def _assert_format_exists(file_format, methods): - """Checks whether the given file format exists in 'methods'. - """ - - try: - return methods[file_format] - except KeyError: - formats = ', '.join(sorted(methods.keys())) - raise ValueError('Unsupported format: %r, try one of %s' % (file_format, - formats)) - - def save_pkcs1(self, format='PEM'): - """Saves the public key in PKCS#1 DER or PEM format. - - :param format: the format to save; 'PEM' or 'DER' - :returns: the DER- or PEM-encoded public key. - """ - - methods = { - 'PEM': self._save_pkcs1_pem, - 'DER': self._save_pkcs1_der, - } - - method = self._assert_format_exists(format, methods) - return method() - - def blind(self, message, r): - """Performs blinding on the message using random number 'r'. - - :param message: the message, as integer, to blind. - :type message: int - :param r: the random number to blind with. - :type r: int - :return: the blinded message. - :rtype: int - - The blinding is such that message = unblind(decrypt(blind(encrypt(message))). - - See https://en.wikipedia.org/wiki/Blinding_%28cryptography%29 - """ - - return (message * pow(r, self.e, self.n)) % self.n - - def unblind(self, blinded, r): - """Performs blinding on the message using random number 'r'. - - :param blinded: the blinded message, as integer, to unblind. - :param r: the random number to unblind with. - :return: the original message. - - The blinding is such that message = unblind(decrypt(blind(encrypt(message))). - - See https://en.wikipedia.org/wiki/Blinding_%28cryptography%29 - """ - - return (rsa.common.inverse(r, self.n) * blinded) % self.n - - -class PublicKey(AbstractKey): - """Represents a public RSA key. - - This key is also known as the 'encryption key'. It contains the 'n' and 'e' - values. - - Supports attributes as well as dictionary-like access. Attribute accesss is - faster, though. - - >>> PublicKey(5, 3) - PublicKey(5, 3) - - >>> key = PublicKey(5, 3) - >>> key.n - 5 - >>> key['n'] - 5 - >>> key.e - 3 - >>> key['e'] - 3 - - """ - - __slots__ = ('n', 'e') - - def __getitem__(self, key): - return getattr(self, key) - - def __repr__(self): - return 'PublicKey(%i, %i)' % (self.n, self.e) - - def __getstate__(self): - """Returns the key as tuple for pickling.""" - return self.n, self.e - - def __setstate__(self, state): - """Sets the key from tuple.""" - self.n, self.e = state - - def __eq__(self, other): - if other is None: - return False - - if not isinstance(other, PublicKey): - return False - - return self.n == other.n and self.e == other.e - - def __ne__(self, other): - return not (self == other) - - @classmethod - def _load_pkcs1_der(cls, keyfile): - """Loads a key in PKCS#1 DER format. - - :param keyfile: contents of a DER-encoded file that contains the public - key. - :return: a PublicKey object - - First let's construct a DER encoded key: - - >>> import base64 - >>> b64der = 'MAwCBQCNGmYtAgMBAAE=' - >>> der = base64.standard_b64decode(b64der) - - This loads the file: - - >>> PublicKey._load_pkcs1_der(der) - PublicKey(2367317549, 65537) - - """ - - from pyasn1.codec.der import decoder - from rsa.asn1 import AsnPubKey - - (priv, _) = decoder.decode(keyfile, asn1Spec=AsnPubKey()) - return cls(n=int(priv['modulus']), e=int(priv['publicExponent'])) - - def _save_pkcs1_der(self): - """Saves the public key in PKCS#1 DER format. - - @returns: the DER-encoded public key. - """ - - from pyasn1.codec.der import encoder - from rsa.asn1 import AsnPubKey - - # Create the ASN object - asn_key = AsnPubKey() - asn_key.setComponentByName('modulus', self.n) - asn_key.setComponentByName('publicExponent', self.e) - - return encoder.encode(asn_key) - - @classmethod - def _load_pkcs1_pem(cls, keyfile): - """Loads a PKCS#1 PEM-encoded public key file. - - The contents of the file before the "-----BEGIN RSA PUBLIC KEY-----" and - after the "-----END RSA PUBLIC KEY-----" lines is ignored. - - :param keyfile: contents of a PEM-encoded file that contains the public - key. - :return: a PublicKey object - """ - - der = rsa.pem.load_pem(keyfile, 'RSA PUBLIC KEY') - return cls._load_pkcs1_der(der) - - def _save_pkcs1_pem(self): - """Saves a PKCS#1 PEM-encoded public key file. - - :return: contents of a PEM-encoded file that contains the public key. - """ - - der = self._save_pkcs1_der() - return rsa.pem.save_pem(der, 'RSA PUBLIC KEY') - - @classmethod - def load_pkcs1_openssl_pem(cls, keyfile): - """Loads a PKCS#1.5 PEM-encoded public key file from OpenSSL. - - These files can be recognised in that they start with BEGIN PUBLIC KEY - rather than BEGIN RSA PUBLIC KEY. - - The contents of the file before the "-----BEGIN PUBLIC KEY-----" and - after the "-----END PUBLIC KEY-----" lines is ignored. - - :param keyfile: contents of a PEM-encoded file that contains the public - key, from OpenSSL. - :return: a PublicKey object - """ - - der = rsa.pem.load_pem(keyfile, 'PUBLIC KEY') - return cls.load_pkcs1_openssl_der(der) - - @classmethod - def load_pkcs1_openssl_der(cls, keyfile): - """Loads a PKCS#1 DER-encoded public key file from OpenSSL. - - :param keyfile: contents of a DER-encoded file that contains the public - key, from OpenSSL. - :return: a PublicKey object - - """ - - from rsa.asn1 import OpenSSLPubKey - from pyasn1.codec.der import decoder - from pyasn1.type import univ - - (keyinfo, _) = decoder.decode(keyfile, asn1Spec=OpenSSLPubKey()) - - if keyinfo['header']['oid'] != univ.ObjectIdentifier('1.2.840.113549.1.1.1'): - raise TypeError("This is not a DER-encoded OpenSSL-compatible public key") - - return cls._load_pkcs1_der(keyinfo['key'][1:]) - - -class PrivateKey(AbstractKey): - """Represents a private RSA key. - - This key is also known as the 'decryption key'. It contains the 'n', 'e', - 'd', 'p', 'q' and other values. - - Supports attributes as well as dictionary-like access. Attribute accesss is - faster, though. - - >>> PrivateKey(3247, 65537, 833, 191, 17) - PrivateKey(3247, 65537, 833, 191, 17) - - exp1, exp2 and coef can be given, but if None or omitted they will be calculated: - - >>> pk = PrivateKey(3727264081, 65537, 3349121513, 65063, 57287, exp2=4) - >>> pk.exp1 - 55063 - >>> pk.exp2 # this is of course not a correct value, but it is the one we passed. - 4 - >>> pk.coef - 50797 - - If you give exp1, exp2 or coef, they will be used as-is: - - >>> pk = PrivateKey(1, 2, 3, 4, 5, 6, 7, 8) - >>> pk.exp1 - 6 - >>> pk.exp2 - 7 - >>> pk.coef - 8 - - """ - - __slots__ = ('n', 'e', 'd', 'p', 'q', 'exp1', 'exp2', 'coef') - - def __init__(self, n, e, d, p, q, exp1=None, exp2=None, coef=None): - AbstractKey.__init__(self, n, e) - self.d = d - self.p = p - self.q = q - - # Calculate the other values if they aren't supplied - if exp1 is None: - self.exp1 = int(d % (p - 1)) - else: - self.exp1 = exp1 - - if exp2 is None: - self.exp2 = int(d % (q - 1)) - else: - self.exp2 = exp2 - - if coef is None: - self.coef = rsa.common.inverse(q, p) - else: - self.coef = coef - - def __getitem__(self, key): - return getattr(self, key) - - def __repr__(self): - return 'PrivateKey(%(n)i, %(e)i, %(d)i, %(p)i, %(q)i)' % self - - def __getstate__(self): - """Returns the key as tuple for pickling.""" - return self.n, self.e, self.d, self.p, self.q, self.exp1, self.exp2, self.coef - - def __setstate__(self, state): - """Sets the key from tuple.""" - self.n, self.e, self.d, self.p, self.q, self.exp1, self.exp2, self.coef = state - - def __eq__(self, other): - if other is None: - return False - - if not isinstance(other, PrivateKey): - return False - - return (self.n == other.n and - self.e == other.e and - self.d == other.d and - self.p == other.p and - self.q == other.q and - self.exp1 == other.exp1 and - self.exp2 == other.exp2 and - self.coef == other.coef) - - def __ne__(self, other): - return not (self == other) - - def blinded_decrypt(self, encrypted): - """Decrypts the message using blinding to prevent side-channel attacks. - - :param encrypted: the encrypted message - :type encrypted: int - - :returns: the decrypted message - :rtype: int - """ - - blind_r = rsa.randnum.randint(self.n - 1) - blinded = self.blind(encrypted, blind_r) # blind before decrypting - decrypted = rsa.core.decrypt_int(blinded, self.d, self.n) - - return self.unblind(decrypted, blind_r) - - def blinded_encrypt(self, message): - """Encrypts the message using blinding to prevent side-channel attacks. - - :param message: the message to encrypt - :type message: int - - :returns: the encrypted message - :rtype: int - """ - - blind_r = rsa.randnum.randint(self.n - 1) - blinded = self.blind(message, blind_r) # blind before encrypting - encrypted = rsa.core.encrypt_int(blinded, self.d, self.n) - return self.unblind(encrypted, blind_r) - - @classmethod - def _load_pkcs1_der(cls, keyfile): - """Loads a key in PKCS#1 DER format. - - :param keyfile: contents of a DER-encoded file that contains the private - key. - :return: a PrivateKey object - - First let's construct a DER encoded key: - - >>> import base64 - >>> b64der = 'MC4CAQACBQDeKYlRAgMBAAECBQDHn4npAgMA/icCAwDfxwIDANcXAgInbwIDAMZt' - >>> der = base64.standard_b64decode(b64der) - - This loads the file: - - >>> PrivateKey._load_pkcs1_der(der) - PrivateKey(3727264081, 65537, 3349121513, 65063, 57287) - - """ - - from pyasn1.codec.der import decoder - (priv, _) = decoder.decode(keyfile) - - # ASN.1 contents of DER encoded private key: - # - # RSAPrivateKey ::= SEQUENCE { - # version Version, - # modulus INTEGER, -- n - # publicExponent INTEGER, -- e - # privateExponent INTEGER, -- d - # prime1 INTEGER, -- p - # prime2 INTEGER, -- q - # exponent1 INTEGER, -- d mod (p-1) - # exponent2 INTEGER, -- d mod (q-1) - # coefficient INTEGER, -- (inverse of q) mod p - # otherPrimeInfos OtherPrimeInfos OPTIONAL - # } - - if priv[0] != 0: - raise ValueError('Unable to read this file, version %s != 0' % priv[0]) - - as_ints = tuple(int(x) for x in priv[1:9]) - return cls(*as_ints) - - def _save_pkcs1_der(self): - """Saves the private key in PKCS#1 DER format. - - @returns: the DER-encoded private key. - """ - - from pyasn1.type import univ, namedtype - from pyasn1.codec.der import encoder - - class AsnPrivKey(univ.Sequence): - componentType = namedtype.NamedTypes( - namedtype.NamedType('version', univ.Integer()), - namedtype.NamedType('modulus', univ.Integer()), - namedtype.NamedType('publicExponent', univ.Integer()), - namedtype.NamedType('privateExponent', univ.Integer()), - namedtype.NamedType('prime1', univ.Integer()), - namedtype.NamedType('prime2', univ.Integer()), - namedtype.NamedType('exponent1', univ.Integer()), - namedtype.NamedType('exponent2', univ.Integer()), - namedtype.NamedType('coefficient', univ.Integer()), - ) - - # Create the ASN object - asn_key = AsnPrivKey() - asn_key.setComponentByName('version', 0) - asn_key.setComponentByName('modulus', self.n) - asn_key.setComponentByName('publicExponent', self.e) - asn_key.setComponentByName('privateExponent', self.d) - asn_key.setComponentByName('prime1', self.p) - asn_key.setComponentByName('prime2', self.q) - asn_key.setComponentByName('exponent1', self.exp1) - asn_key.setComponentByName('exponent2', self.exp2) - asn_key.setComponentByName('coefficient', self.coef) - - return encoder.encode(asn_key) - - @classmethod - def _load_pkcs1_pem(cls, keyfile): - """Loads a PKCS#1 PEM-encoded private key file. - - The contents of the file before the "-----BEGIN RSA PRIVATE KEY-----" and - after the "-----END RSA PRIVATE KEY-----" lines is ignored. - - :param keyfile: contents of a PEM-encoded file that contains the private - key. - :return: a PrivateKey object - """ - - der = rsa.pem.load_pem(keyfile, b('RSA PRIVATE KEY')) - return cls._load_pkcs1_der(der) - - def _save_pkcs1_pem(self): - """Saves a PKCS#1 PEM-encoded private key file. - - :return: contents of a PEM-encoded file that contains the private key. - """ - - der = self._save_pkcs1_der() - return rsa.pem.save_pem(der, b('RSA PRIVATE KEY')) - - -def find_p_q(nbits, getprime_func=rsa.prime.getprime, accurate=True): - """Returns a tuple of two different primes of nbits bits each. - - The resulting p * q has exacty 2 * nbits bits, and the returned p and q - will not be equal. - - :param nbits: the number of bits in each of p and q. - :param getprime_func: the getprime function, defaults to - :py:func:`rsa.prime.getprime`. - - *Introduced in Python-RSA 3.1* - - :param accurate: whether to enable accurate mode or not. - :returns: (p, q), where p > q - - >>> (p, q) = find_p_q(128) - >>> from rsa import common - >>> common.bit_size(p * q) - 256 - - When not in accurate mode, the number of bits can be slightly less - - >>> (p, q) = find_p_q(128, accurate=False) - >>> from rsa import common - >>> common.bit_size(p * q) <= 256 - True - >>> common.bit_size(p * q) > 240 - True - - """ - - total_bits = nbits * 2 - - # Make sure that p and q aren't too close or the factoring programs can - # factor n. - shift = nbits // 16 - pbits = nbits + shift - qbits = nbits - shift - - # Choose the two initial primes - log.debug('find_p_q(%i): Finding p', nbits) - p = getprime_func(pbits) - log.debug('find_p_q(%i): Finding q', nbits) - q = getprime_func(qbits) - - def is_acceptable(p, q): - """Returns True iff p and q are acceptable: - - - p and q differ - - (p * q) has the right nr of bits (when accurate=True) - """ - - if p == q: - return False - - if not accurate: - return True - - # Make sure we have just the right amount of bits - found_size = rsa.common.bit_size(p * q) - return total_bits == found_size - - # Keep choosing other primes until they match our requirements. - change_p = False - while not is_acceptable(p, q): - # Change p on one iteration and q on the other - if change_p: - p = getprime_func(pbits) - else: - q = getprime_func(qbits) - - change_p = not change_p - - # We want p > q as described on - # http://www.di-mgt.com.au/rsa_alg.html#crt - return max(p, q), min(p, q) - - -def calculate_keys_custom_exponent(p, q, exponent): - """Calculates an encryption and a decryption key given p, q and an exponent, - and returns them as a tuple (e, d) - - :param p: the first large prime - :param q: the second large prime - :param exponent: the exponent for the key; only change this if you know - what you're doing, as the exponent influences how difficult your - private key can be cracked. A very common choice for e is 65537. - :type exponent: int - - """ - - phi_n = (p - 1) * (q - 1) - - try: - d = rsa.common.inverse(exponent, phi_n) - except ValueError: - raise ValueError("e (%d) and phi_n (%d) are not relatively prime" % - (exponent, phi_n)) - - if (exponent * d) % phi_n != 1: - raise ValueError("e (%d) and d (%d) are not mult. inv. modulo " - "phi_n (%d)" % (exponent, d, phi_n)) - - return exponent, d - - -def calculate_keys(p, q): - """Calculates an encryption and a decryption key given p and q, and - returns them as a tuple (e, d) - - :param p: the first large prime - :param q: the second large prime - - :return: tuple (e, d) with the encryption and decryption exponents. - """ - - return calculate_keys_custom_exponent(p, q, DEFAULT_EXPONENT) - - -def gen_keys(nbits, getprime_func, accurate=True, exponent=DEFAULT_EXPONENT): - """Generate RSA keys of nbits bits. Returns (p, q, e, d). - - Note: this can take a long time, depending on the key size. - - :param nbits: the total number of bits in ``p`` and ``q``. Both ``p`` and - ``q`` will use ``nbits/2`` bits. - :param getprime_func: either :py:func:`rsa.prime.getprime` or a function - with similar signature. - :param exponent: the exponent for the key; only change this if you know - what you're doing, as the exponent influences how difficult your - private key can be cracked. A very common choice for e is 65537. - :type exponent: int - """ - - # Regenerate p and q values, until calculate_keys doesn't raise a - # ValueError. - while True: - (p, q) = find_p_q(nbits // 2, getprime_func, accurate) - try: - (e, d) = calculate_keys_custom_exponent(p, q, exponent=exponent) - break - except ValueError: - pass - - return p, q, e, d - - -def newkeys(nbits, accurate=True, poolsize=1, exponent=DEFAULT_EXPONENT): - """Generates public and private keys, and returns them as (pub, priv). - - The public key is also known as the 'encryption key', and is a - :py:class:`rsa.PublicKey` object. The private key is also known as the - 'decryption key' and is a :py:class:`rsa.PrivateKey` object. - - :param nbits: the number of bits required to store ``n = p*q``. - :param accurate: when True, ``n`` will have exactly the number of bits you - asked for. However, this makes key generation much slower. When False, - `n`` may have slightly less bits. - :param poolsize: the number of processes to use to generate the prime - numbers. If set to a number > 1, a parallel algorithm will be used. - This requires Python 2.6 or newer. - :param exponent: the exponent for the key; only change this if you know - what you're doing, as the exponent influences how difficult your - private key can be cracked. A very common choice for e is 65537. - :type exponent: int - - :returns: a tuple (:py:class:`rsa.PublicKey`, :py:class:`rsa.PrivateKey`) - - The ``poolsize`` parameter was added in *Python-RSA 3.1* and requires - Python 2.6 or newer. - - """ - - if nbits < 16: - raise ValueError('Key too small') - - if poolsize < 1: - raise ValueError('Pool size (%i) should be >= 1' % poolsize) - - # Determine which getprime function to use - if poolsize > 1: - from rsa import parallel - import functools - - getprime_func = functools.partial(parallel.getprime, poolsize=poolsize) - else: - getprime_func = rsa.prime.getprime - - # Generate the key components - (p, q, e, d) = gen_keys(nbits, getprime_func, accurate=accurate, exponent=exponent) - - # Create the key objects - n = p * q - - return ( - PublicKey(n, e), - PrivateKey(n, e, d, p, q) - ) - - -__all__ = ['PublicKey', 'PrivateKey', 'newkeys'] - -if __name__ == '__main__': - import doctest - - try: - for count in range(100): - (failures, tests) = doctest.testmod() - if failures: - break - - if (count and count % 10 == 0) or count == 1: - print('%i times' % count) - except KeyboardInterrupt: - print('Aborted') - else: - print('Doctests done') diff --git a/src/lib/rsa/parallel.py b/src/lib/rsa/parallel.py deleted file mode 100644 index edc924fd..00000000 --- a/src/lib/rsa/parallel.py +++ /dev/null @@ -1,100 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2011 Sybren A. Stüvel -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Functions for parallel computation on multiple cores. - -Introduced in Python-RSA 3.1. - -.. note:: - - Requires Python 2.6 or newer. - -""" - -from __future__ import print_function - -import multiprocessing as mp - -import rsa.prime -import rsa.randnum - - -def _find_prime(nbits, pipe): - while True: - integer = rsa.randnum.read_random_odd_int(nbits) - - # Test for primeness - if rsa.prime.is_prime(integer): - pipe.send(integer) - return - - -def getprime(nbits, poolsize): - """Returns a prime number that can be stored in 'nbits' bits. - - Works in multiple threads at the same time. - - >>> p = getprime(128, 3) - >>> rsa.prime.is_prime(p-1) - False - >>> rsa.prime.is_prime(p) - True - >>> rsa.prime.is_prime(p+1) - False - - >>> from rsa import common - >>> common.bit_size(p) == 128 - True - - """ - - (pipe_recv, pipe_send) = mp.Pipe(duplex=False) - - # Create processes - try: - procs = [mp.Process(target=_find_prime, args=(nbits, pipe_send)) - for _ in range(poolsize)] - # Start processes - for p in procs: - p.start() - - result = pipe_recv.recv() - finally: - pipe_recv.close() - pipe_send.close() - - # Terminate processes - for p in procs: - p.terminate() - - return result - - -__all__ = ['getprime'] - -if __name__ == '__main__': - print('Running doctests 1000x or until failure') - import doctest - - for count in range(100): - (failures, tests) = doctest.testmod() - if failures: - break - - if count and count % 10 == 0: - print('%i times' % count) - - print('Doctests done') diff --git a/src/lib/rsa/pem.py b/src/lib/rsa/pem.py deleted file mode 100644 index 0f68cb2a..00000000 --- a/src/lib/rsa/pem.py +++ /dev/null @@ -1,125 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2011 Sybren A. Stüvel -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Functions that load and write PEM-encoded files.""" - -import base64 -from rsa._compat import b, is_bytes - - -def _markers(pem_marker): - """ - Returns the start and end PEM markers - """ - - if is_bytes(pem_marker): - pem_marker = pem_marker.decode('utf-8') - - return (b('-----BEGIN %s-----' % pem_marker), - b('-----END %s-----' % pem_marker)) - - -def load_pem(contents, pem_marker): - """Loads a PEM file. - - :param contents: the contents of the file to interpret - :param pem_marker: the marker of the PEM content, such as 'RSA PRIVATE KEY' - when your file has '-----BEGIN RSA PRIVATE KEY-----' and - '-----END RSA PRIVATE KEY-----' markers. - - :return: the base64-decoded content between the start and end markers. - - @raise ValueError: when the content is invalid, for example when the start - marker cannot be found. - - """ - - # We want bytes, not text. If it's text, it can be converted to ASCII bytes. - if not is_bytes(contents): - contents = contents.encode('ascii') - - (pem_start, pem_end) = _markers(pem_marker) - - pem_lines = [] - in_pem_part = False - - for line in contents.splitlines(): - line = line.strip() - - # Skip empty lines - if not line: - continue - - # Handle start marker - if line == pem_start: - if in_pem_part: - raise ValueError('Seen start marker "%s" twice' % pem_start) - - in_pem_part = True - continue - - # Skip stuff before first marker - if not in_pem_part: - continue - - # Handle end marker - if in_pem_part and line == pem_end: - in_pem_part = False - break - - # Load fields - if b(':') in line: - continue - - pem_lines.append(line) - - # Do some sanity checks - if not pem_lines: - raise ValueError('No PEM start marker "%s" found' % pem_start) - - if in_pem_part: - raise ValueError('No PEM end marker "%s" found' % pem_end) - - # Base64-decode the contents - pem = b('').join(pem_lines) - return base64.standard_b64decode(pem) - - -def save_pem(contents, pem_marker): - """Saves a PEM file. - - :param contents: the contents to encode in PEM format - :param pem_marker: the marker of the PEM content, such as 'RSA PRIVATE KEY' - when your file has '-----BEGIN RSA PRIVATE KEY-----' and - '-----END RSA PRIVATE KEY-----' markers. - - :return: the base64-encoded content between the start and end markers. - - """ - - (pem_start, pem_end) = _markers(pem_marker) - - b64 = base64.standard_b64encode(contents).replace(b('\n'), b('')) - pem_lines = [pem_start] - - for block_start in range(0, len(b64), 64): - block = b64[block_start:block_start + 64] - pem_lines.append(block) - - pem_lines.append(pem_end) - pem_lines.append(b('')) - - return b('\n').join(pem_lines) diff --git a/src/lib/rsa/pkcs1.py b/src/lib/rsa/pkcs1.py deleted file mode 100644 index 28f0dc54..00000000 --- a/src/lib/rsa/pkcs1.py +++ /dev/null @@ -1,381 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2011 Sybren A. Stüvel -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Functions for PKCS#1 version 1.5 encryption and signing - -This module implements certain functionality from PKCS#1 version 1.5. For a -very clear example, read http://www.di-mgt.com.au/rsa_alg.html#pkcs1schemes - -At least 8 bytes of random padding is used when encrypting a message. This makes -these methods much more secure than the ones in the ``rsa`` module. - -WARNING: this module leaks information when decryption fails. The exceptions -that are raised contain the Python traceback information, which can be used to -deduce where in the process the failure occurred. DO NOT PASS SUCH INFORMATION -to your users. -""" - -import hashlib -import os - -from rsa._compat import b -from rsa import common, transform, core - -# ASN.1 codes that describe the hash algorithm used. -HASH_ASN1 = { - 'MD5': b('\x30\x20\x30\x0c\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x05\x05\x00\x04\x10'), - 'SHA-1': b('\x30\x21\x30\x09\x06\x05\x2b\x0e\x03\x02\x1a\x05\x00\x04\x14'), - 'SHA-256': b('\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00\x04\x20'), - 'SHA-384': b('\x30\x41\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x02\x05\x00\x04\x30'), - 'SHA-512': b('\x30\x51\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x03\x05\x00\x04\x40'), -} - -HASH_METHODS = { - 'MD5': hashlib.md5, - 'SHA-1': hashlib.sha1, - 'SHA-256': hashlib.sha256, - 'SHA-384': hashlib.sha384, - 'SHA-512': hashlib.sha512, -} - - -class CryptoError(Exception): - """Base class for all exceptions in this module.""" - - -class DecryptionError(CryptoError): - """Raised when decryption fails.""" - - -class VerificationError(CryptoError): - """Raised when verification fails.""" - - -def _pad_for_encryption(message, target_length): - r"""Pads the message for encryption, returning the padded message. - - :return: 00 02 RANDOM_DATA 00 MESSAGE - - >>> block = _pad_for_encryption(b'hello', 16) - >>> len(block) - 16 - >>> block[0:2] - b'\x00\x02' - >>> block[-6:] - b'\x00hello' - - """ - - max_msglength = target_length - 11 - msglength = len(message) - - if msglength > max_msglength: - raise OverflowError('%i bytes needed for message, but there is only' - ' space for %i' % (msglength, max_msglength)) - - # Get random padding - padding = b('') - padding_length = target_length - msglength - 3 - - # We remove 0-bytes, so we'll end up with less padding than we've asked for, - # so keep adding data until we're at the correct length. - while len(padding) < padding_length: - needed_bytes = padding_length - len(padding) - - # Always read at least 8 bytes more than we need, and trim off the rest - # after removing the 0-bytes. This increases the chance of getting - # enough bytes, especially when needed_bytes is small - new_padding = os.urandom(needed_bytes + 5) - new_padding = new_padding.replace(b('\x00'), b('')) - padding = padding + new_padding[:needed_bytes] - - assert len(padding) == padding_length - - return b('').join([b('\x00\x02'), - padding, - b('\x00'), - message]) - - -def _pad_for_signing(message, target_length): - r"""Pads the message for signing, returning the padded message. - - The padding is always a repetition of FF bytes. - - :return: 00 01 PADDING 00 MESSAGE - - >>> block = _pad_for_signing(b'hello', 16) - >>> len(block) - 16 - >>> block[0:2] - b'\x00\x01' - >>> block[-6:] - b'\x00hello' - >>> block[2:-6] - b'\xff\xff\xff\xff\xff\xff\xff\xff' - - """ - - max_msglength = target_length - 11 - msglength = len(message) - - if msglength > max_msglength: - raise OverflowError('%i bytes needed for message, but there is only' - ' space for %i' % (msglength, max_msglength)) - - padding_length = target_length - msglength - 3 - - return b('').join([b('\x00\x01'), - padding_length * b('\xff'), - b('\x00'), - message]) - - -def encrypt(message, pub_key): - """Encrypts the given message using PKCS#1 v1.5 - - :param message: the message to encrypt. Must be a byte string no longer than - ``k-11`` bytes, where ``k`` is the number of bytes needed to encode - the ``n`` component of the public key. - :param pub_key: the :py:class:`rsa.PublicKey` to encrypt with. - :raise OverflowError: when the message is too large to fit in the padded - block. - - >>> from rsa import key, common - >>> (pub_key, priv_key) = key.newkeys(256) - >>> message = b'hello' - >>> crypto = encrypt(message, pub_key) - - The crypto text should be just as long as the public key 'n' component: - - >>> len(crypto) == common.byte_size(pub_key.n) - True - - """ - - keylength = common.byte_size(pub_key.n) - padded = _pad_for_encryption(message, keylength) - - payload = transform.bytes2int(padded) - encrypted = core.encrypt_int(payload, pub_key.e, pub_key.n) - block = transform.int2bytes(encrypted, keylength) - - return block - - -def decrypt(crypto, priv_key): - r"""Decrypts the given message using PKCS#1 v1.5 - - The decryption is considered 'failed' when the resulting cleartext doesn't - start with the bytes 00 02, or when the 00 byte between the padding and - the message cannot be found. - - :param crypto: the crypto text as returned by :py:func:`rsa.encrypt` - :param priv_key: the :py:class:`rsa.PrivateKey` to decrypt with. - :raise DecryptionError: when the decryption fails. No details are given as - to why the code thinks the decryption fails, as this would leak - information about the private key. - - - >>> import rsa - >>> (pub_key, priv_key) = rsa.newkeys(256) - - It works with strings: - - >>> crypto = encrypt(b'hello', pub_key) - >>> decrypt(crypto, priv_key) - b'hello' - - And with binary data: - - >>> crypto = encrypt(b'\x00\x00\x00\x00\x01', pub_key) - >>> decrypt(crypto, priv_key) - b'\x00\x00\x00\x00\x01' - - Altering the encrypted information will *likely* cause a - :py:class:`rsa.pkcs1.DecryptionError`. If you want to be *sure*, use - :py:func:`rsa.sign`. - - - .. warning:: - - Never display the stack trace of a - :py:class:`rsa.pkcs1.DecryptionError` exception. It shows where in the - code the exception occurred, and thus leaks information about the key. - It's only a tiny bit of information, but every bit makes cracking the - keys easier. - - >>> crypto = encrypt(b'hello', pub_key) - >>> crypto = crypto[0:5] + b'X' + crypto[6:] # change a byte - >>> decrypt(crypto, priv_key) - Traceback (most recent call last): - ... - rsa.pkcs1.DecryptionError: Decryption failed - - """ - - blocksize = common.byte_size(priv_key.n) - encrypted = transform.bytes2int(crypto) - decrypted = priv_key.blinded_decrypt(encrypted) - cleartext = transform.int2bytes(decrypted, blocksize) - - # If we can't find the cleartext marker, decryption failed. - if cleartext[0:2] != b('\x00\x02'): - raise DecryptionError('Decryption failed') - - # Find the 00 separator between the padding and the message - try: - sep_idx = cleartext.index(b('\x00'), 2) - except ValueError: - raise DecryptionError('Decryption failed') - - return cleartext[sep_idx + 1:] - - -def sign(message, priv_key, hash): - """Signs the message with the private key. - - Hashes the message, then signs the hash with the given key. This is known - as a "detached signature", because the message itself isn't altered. - - :param message: the message to sign. Can be an 8-bit string or a file-like - object. If ``message`` has a ``read()`` method, it is assumed to be a - file-like object. - :param priv_key: the :py:class:`rsa.PrivateKey` to sign with - :param hash: the hash method used on the message. Use 'MD5', 'SHA-1', - 'SHA-256', 'SHA-384' or 'SHA-512'. - :return: a message signature block. - :raise OverflowError: if the private key is too small to contain the - requested hash. - - """ - - # Get the ASN1 code for this hash method - if hash not in HASH_ASN1: - raise ValueError('Invalid hash method: %s' % hash) - asn1code = HASH_ASN1[hash] - - # Calculate the hash - hash = _hash(message, hash) - - # Encrypt the hash with the private key - cleartext = asn1code + hash - keylength = common.byte_size(priv_key.n) - padded = _pad_for_signing(cleartext, keylength) - - payload = transform.bytes2int(padded) - encrypted = priv_key.blinded_encrypt(payload) - block = transform.int2bytes(encrypted, keylength) - - return block - - -def verify(message, signature, pub_key): - """Verifies that the signature matches the message. - - The hash method is detected automatically from the signature. - - :param message: the signed message. Can be an 8-bit string or a file-like - object. If ``message`` has a ``read()`` method, it is assumed to be a - file-like object. - :param signature: the signature block, as created with :py:func:`rsa.sign`. - :param pub_key: the :py:class:`rsa.PublicKey` of the person signing the message. - :raise VerificationError: when the signature doesn't match the message. - - """ - - keylength = common.byte_size(pub_key.n) - encrypted = transform.bytes2int(signature) - decrypted = core.decrypt_int(encrypted, pub_key.e, pub_key.n) - clearsig = transform.int2bytes(decrypted, keylength) - - # Get the hash method - method_name = _find_method_hash(clearsig) - message_hash = _hash(message, method_name) - - # Reconstruct the expected padded hash - cleartext = HASH_ASN1[method_name] + message_hash - expected = _pad_for_signing(cleartext, keylength) - - # Compare with the signed one - if expected != clearsig: - raise VerificationError('Verification failed') - - return True - - -def _hash(message, method_name): - """Returns the message digest. - - :param message: the signed message. Can be an 8-bit string or a file-like - object. If ``message`` has a ``read()`` method, it is assumed to be a - file-like object. - :param method_name: the hash method, must be a key of - :py:const:`HASH_METHODS`. - - """ - - if method_name not in HASH_METHODS: - raise ValueError('Invalid hash method: %s' % method_name) - - method = HASH_METHODS[method_name] - hasher = method() - - if hasattr(message, 'read') and hasattr(message.read, '__call__'): - # Late import to prevent DeprecationWarnings. - from . import varblock - - # read as 1K blocks - for block in varblock.yield_fixedblocks(message, 1024): - hasher.update(block) - else: - # hash the message object itself. - hasher.update(message) - - return hasher.digest() - - -def _find_method_hash(clearsig): - """Finds the hash method. - - :param clearsig: full padded ASN1 and hash. - :return: the used hash method. - :raise VerificationFailed: when the hash method cannot be found - """ - - for (hashname, asn1code) in HASH_ASN1.items(): - if asn1code in clearsig: - return hashname - - raise VerificationError('Verification failed') - - -__all__ = ['encrypt', 'decrypt', 'sign', 'verify', - 'DecryptionError', 'VerificationError', 'CryptoError'] - -if __name__ == '__main__': - print('Running doctests 1000x or until failure') - import doctest - - for count in range(1000): - (failures, tests) = doctest.testmod() - if failures: - break - - if count and count % 100 == 0: - print('%i times' % count) - - print('Doctests done') diff --git a/src/lib/rsa/prime.py b/src/lib/rsa/prime.py deleted file mode 100644 index 6f23f9da..00000000 --- a/src/lib/rsa/prime.py +++ /dev/null @@ -1,178 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2011 Sybren A. Stüvel -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Numerical functions related to primes. - -Implementation based on the book Algorithm Design by Michael T. Goodrich and -Roberto Tamassia, 2002. -""" - -import rsa.randnum - -__all__ = ['getprime', 'are_relatively_prime'] - - -def gcd(p, q): - """Returns the greatest common divisor of p and q - - >>> gcd(48, 180) - 12 - """ - - while q != 0: - (p, q) = (q, p % q) - return p - - -def miller_rabin_primality_testing(n, k): - """Calculates whether n is composite (which is always correct) or prime - (which theoretically is incorrect with error probability 4**-k), by - applying Miller-Rabin primality testing. - - For reference and implementation example, see: - https://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test - - :param n: Integer to be tested for primality. - :type n: int - :param k: Number of rounds (witnesses) of Miller-Rabin testing. - :type k: int - :return: False if the number is composite, True if it's probably prime. - :rtype: bool - """ - - # prevent potential infinite loop when d = 0 - if n < 2: - return False - - # Decompose (n - 1) to write it as (2 ** r) * d - # While d is even, divide it by 2 and increase the exponent. - d = n - 1 - r = 0 - - while not (d & 1): - r += 1 - d >>= 1 - - # Test k witnesses. - for _ in range(k): - # Generate random integer a, where 2 <= a <= (n - 2) - a = rsa.randnum.randint(n - 4) + 2 - - x = pow(a, d, n) - if x == 1 or x == n - 1: - continue - - for _ in range(r - 1): - x = pow(x, 2, n) - if x == 1: - # n is composite. - return False - if x == n - 1: - # Exit inner loop and continue with next witness. - break - else: - # If loop doesn't break, n is composite. - return False - - return True - - -def is_prime(number): - """Returns True if the number is prime, and False otherwise. - - >>> is_prime(2) - True - >>> is_prime(42) - False - >>> is_prime(41) - True - >>> [x for x in range(901, 1000) if is_prime(x)] - [907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997] - """ - - # Check for small numbers. - if number < 10: - return number in [2, 3, 5, 7] - - # Check for even numbers. - if not (number & 1): - return False - - # According to NIST FIPS 186-4, Appendix C, Table C.3, minimum number of - # rounds of M-R testing, using an error probability of 2 ** (-100), for - # different p, q bitsizes are: - # * p, q bitsize: 512; rounds: 7 - # * p, q bitsize: 1024; rounds: 4 - # * p, q bitsize: 1536; rounds: 3 - # See: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf - return miller_rabin_primality_testing(number, 7) - - -def getprime(nbits): - """Returns a prime number that can be stored in 'nbits' bits. - - >>> p = getprime(128) - >>> is_prime(p-1) - False - >>> is_prime(p) - True - >>> is_prime(p+1) - False - - >>> from rsa import common - >>> common.bit_size(p) == 128 - True - """ - - assert nbits > 3 # the loop wil hang on too small numbers - - while True: - integer = rsa.randnum.read_random_odd_int(nbits) - - # Test for primeness - if is_prime(integer): - return integer - - # Retry if not prime - - -def are_relatively_prime(a, b): - """Returns True if a and b are relatively prime, and False if they - are not. - - >>> are_relatively_prime(2, 3) - True - >>> are_relatively_prime(2, 4) - False - """ - - d = gcd(a, b) - return d == 1 - - -if __name__ == '__main__': - print('Running doctests 1000x or until failure') - import doctest - - for count in range(1000): - (failures, tests) = doctest.testmod() - if failures: - break - - if count and count % 100 == 0: - print('%i times' % count) - - print('Doctests done') diff --git a/src/lib/rsa/randnum.py b/src/lib/rsa/randnum.py deleted file mode 100644 index 3c788a57..00000000 --- a/src/lib/rsa/randnum.py +++ /dev/null @@ -1,98 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2011 Sybren A. Stüvel -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Functions for generating random numbers.""" - -# Source inspired by code by Yesudeep Mangalapilly - -import os - -from rsa import common, transform -from rsa._compat import byte - - -def read_random_bits(nbits): - """Reads 'nbits' random bits. - - If nbits isn't a whole number of bytes, an extra byte will be appended with - only the lower bits set. - """ - - nbytes, rbits = divmod(nbits, 8) - - # Get the random bytes - randomdata = os.urandom(nbytes) - - # Add the remaining random bits - if rbits > 0: - randomvalue = ord(os.urandom(1)) - randomvalue >>= (8 - rbits) - randomdata = byte(randomvalue) + randomdata - - return randomdata - - -def read_random_int(nbits): - """Reads a random integer of approximately nbits bits. - """ - - randomdata = read_random_bits(nbits) - value = transform.bytes2int(randomdata) - - # Ensure that the number is large enough to just fill out the required - # number of bits. - value |= 1 << (nbits - 1) - - return value - - -def read_random_odd_int(nbits): - """Reads a random odd integer of approximately nbits bits. - - >>> read_random_odd_int(512) & 1 - 1 - """ - - value = read_random_int(nbits) - - # Make sure it's odd - return value | 1 - - -def randint(maxvalue): - """Returns a random integer x with 1 <= x <= maxvalue - - May take a very long time in specific situations. If maxvalue needs N bits - to store, the closer maxvalue is to (2 ** N) - 1, the faster this function - is. - """ - - bit_size = common.bit_size(maxvalue) - - tries = 0 - while True: - value = read_random_int(bit_size) - if value <= maxvalue: - break - - if tries and tries % 10 == 0: - # After a lot of tries to get the right number of bits but still - # smaller than maxvalue, decrease the number of bits by 1. That'll - # dramatically increase the chances to get a large enough number. - bit_size -= 1 - tries += 1 - - return value diff --git a/src/lib/rsa/transform.py b/src/lib/rsa/transform.py deleted file mode 100644 index 16061a94..00000000 --- a/src/lib/rsa/transform.py +++ /dev/null @@ -1,224 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2011 Sybren A. Stüvel -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Data transformation functions. - -From bytes to a number, number to bytes, etc. -""" - -from __future__ import absolute_import - -try: - # We'll use psyco if available on 32-bit architectures to speed up code. - # Using psyco (if available) cuts down the execution time on Python 2.5 - # at least by half. - import psyco - - psyco.full() -except ImportError: - pass - -import binascii -from struct import pack -from rsa import common -from rsa._compat import is_integer, b, byte, get_word_alignment, ZERO_BYTE, EMPTY_BYTE - - -def bytes2int(raw_bytes): - r"""Converts a list of bytes or an 8-bit string to an integer. - - When using unicode strings, encode it to some encoding like UTF8 first. - - >>> (((128 * 256) + 64) * 256) + 15 - 8405007 - >>> bytes2int(b'\x80@\x0f') - 8405007 - - """ - - return int(binascii.hexlify(raw_bytes), 16) - - -def _int2bytes(number, block_size=None): - r"""Converts a number to a string of bytes. - - Usage:: - - >>> _int2bytes(123456789) - b'\x07[\xcd\x15' - >>> bytes2int(_int2bytes(123456789)) - 123456789 - - >>> _int2bytes(123456789, 6) - b'\x00\x00\x07[\xcd\x15' - >>> bytes2int(_int2bytes(123456789, 128)) - 123456789 - - >>> _int2bytes(123456789, 3) - Traceback (most recent call last): - ... - OverflowError: Needed 4 bytes for number, but block size is 3 - - @param number: the number to convert - @param block_size: the number of bytes to output. If the number encoded to - bytes is less than this, the block will be zero-padded. When not given, - the returned block is not padded. - - @throws OverflowError when block_size is given and the number takes up more - bytes than fit into the block. - """ - - # Type checking - if not is_integer(number): - raise TypeError("You must pass an integer for 'number', not %s" % - number.__class__) - - if number < 0: - raise ValueError('Negative numbers cannot be used: %i' % number) - - # Do some bounds checking - if number == 0: - needed_bytes = 1 - raw_bytes = [ZERO_BYTE] - else: - needed_bytes = common.byte_size(number) - raw_bytes = [] - - # You cannot compare None > 0 in Python 3x. It will fail with a TypeError. - if block_size and block_size > 0: - if needed_bytes > block_size: - raise OverflowError('Needed %i bytes for number, but block size ' - 'is %i' % (needed_bytes, block_size)) - - # Convert the number to bytes. - while number > 0: - raw_bytes.insert(0, byte(number & 0xFF)) - number >>= 8 - - # Pad with zeroes to fill the block - if block_size and block_size > 0: - padding = (block_size - needed_bytes) * ZERO_BYTE - else: - padding = EMPTY_BYTE - - return padding + EMPTY_BYTE.join(raw_bytes) - - -def bytes_leading(raw_bytes, needle=ZERO_BYTE): - """ - Finds the number of prefixed byte occurrences in the haystack. - - Useful when you want to deal with padding. - - :param raw_bytes: - Raw bytes. - :param needle: - The byte to count. Default \000. - :returns: - The number of leading needle bytes. - """ - - leading = 0 - # Indexing keeps compatibility between Python 2.x and Python 3.x - _byte = needle[0] - for x in raw_bytes: - if x == _byte: - leading += 1 - else: - break - return leading - - -def int2bytes(number, fill_size=None, chunk_size=None, overflow=False): - """ - Convert an unsigned integer to bytes (base-256 representation):: - - Does not preserve leading zeros if you don't specify a chunk size or - fill size. - - .. NOTE: - You must not specify both fill_size and chunk_size. Only one - of them is allowed. - - :param number: - Integer value - :param fill_size: - If the optional fill size is given the length of the resulting - byte string is expected to be the fill size and will be padded - with prefix zero bytes to satisfy that length. - :param chunk_size: - If optional chunk size is given and greater than zero, pad the front of - the byte string with binary zeros so that the length is a multiple of - ``chunk_size``. - :param overflow: - ``False`` (default). If this is ``True``, no ``OverflowError`` - will be raised when the fill_size is shorter than the length - of the generated byte sequence. Instead the byte sequence will - be returned as is. - :returns: - Raw bytes (base-256 representation). - :raises: - ``OverflowError`` when fill_size is given and the number takes up more - bytes than fit into the block. This requires the ``overflow`` - argument to this function to be set to ``False`` otherwise, no - error will be raised. - """ - - if number < 0: - raise ValueError("Number must be an unsigned integer: %d" % number) - - if fill_size and chunk_size: - raise ValueError("You can either fill or pad chunks, but not both") - - # Ensure these are integers. - number & 1 - - raw_bytes = b('') - - # Pack the integer one machine word at a time into bytes. - num = number - word_bits, _, max_uint, pack_type = get_word_alignment(num) - pack_format = ">%s" % pack_type - while num > 0: - raw_bytes = pack(pack_format, num & max_uint) + raw_bytes - num >>= word_bits - # Obtain the index of the first non-zero byte. - zero_leading = bytes_leading(raw_bytes) - if number == 0: - raw_bytes = ZERO_BYTE - # De-padding. - raw_bytes = raw_bytes[zero_leading:] - - length = len(raw_bytes) - if fill_size and fill_size > 0: - if not overflow and length > fill_size: - raise OverflowError( - "Need %d bytes for number, but fill size is %d" % - (length, fill_size) - ) - raw_bytes = raw_bytes.rjust(fill_size, ZERO_BYTE) - elif chunk_size and chunk_size > 0: - remainder = length % chunk_size - if remainder: - padding_size = chunk_size - remainder - raw_bytes = raw_bytes.rjust(length + padding_size, ZERO_BYTE) - return raw_bytes - - -if __name__ == '__main__': - import doctest - - doctest.testmod() diff --git a/src/lib/rsa/util.py b/src/lib/rsa/util.py deleted file mode 100644 index 29d5eb12..00000000 --- a/src/lib/rsa/util.py +++ /dev/null @@ -1,79 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2011 Sybren A. Stüvel -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Utility functions.""" - -from __future__ import with_statement, print_function - -import sys -from optparse import OptionParser - -import rsa.key - - -def private_to_public(): - """Reads a private key and outputs the corresponding public key.""" - - # Parse the CLI options - parser = OptionParser(usage='usage: %prog [options]', - description='Reads a private key and outputs the ' - 'corresponding public key. Both private and public keys use ' - 'the format described in PKCS#1 v1.5') - - parser.add_option('-i', '--input', dest='infilename', type='string', - help='Input filename. Reads from stdin if not specified') - parser.add_option('-o', '--output', dest='outfilename', type='string', - help='Output filename. Writes to stdout of not specified') - - parser.add_option('--inform', dest='inform', - help='key format of input - default PEM', - choices=('PEM', 'DER'), default='PEM') - - parser.add_option('--outform', dest='outform', - help='key format of output - default PEM', - choices=('PEM', 'DER'), default='PEM') - - (cli, cli_args) = parser.parse_args(sys.argv) - - # Read the input data - if cli.infilename: - print('Reading private key from %s in %s format' % - (cli.infilename, cli.inform), file=sys.stderr) - with open(cli.infilename, 'rb') as infile: - in_data = infile.read() - else: - print('Reading private key from stdin in %s format' % cli.inform, - file=sys.stderr) - in_data = sys.stdin.read().encode('ascii') - - assert type(in_data) == bytes, type(in_data) - - # Take the public fields and create a public key - priv_key = rsa.key.PrivateKey.load_pkcs1(in_data, cli.inform) - pub_key = rsa.key.PublicKey(priv_key.n, priv_key.e) - - # Save to the output file - out_data = pub_key.save_pkcs1(cli.outform) - - if cli.outfilename: - print('Writing public key to %s in %s format' % - (cli.outfilename, cli.outform), file=sys.stderr) - with open(cli.outfilename, 'wb') as outfile: - outfile.write(out_data) - else: - print('Writing public key to stdout in %s format' % cli.outform, - file=sys.stderr) - sys.stdout.write(out_data.decode('ascii')) diff --git a/src/lib/rsa/varblock.py b/src/lib/rsa/varblock.py deleted file mode 100644 index 1c8d8390..00000000 --- a/src/lib/rsa/varblock.py +++ /dev/null @@ -1,179 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2011 Sybren A. Stüvel -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""VARBLOCK file support - -.. deprecated:: 3.4 - - The VARBLOCK format is NOT recommended for general use, has been deprecated since - Python-RSA 3.4, and will be removed in a future release. It's vulnerable to a - number of attacks: - - 1. decrypt/encrypt_bigfile() does not implement `Authenticated encryption`_ nor - uses MACs to verify messages before decrypting public key encrypted messages. - - 2. decrypt/encrypt_bigfile() does not use hybrid encryption (it uses plain RSA) - and has no method for chaining, so block reordering is possible. - - See `issue #19 on Github`_ for more information. - -.. _Authenticated encryption: https://en.wikipedia.org/wiki/Authenticated_encryption -.. _issue #19 on Github: https://github.com/sybrenstuvel/python-rsa/issues/13 - - -The VARBLOCK file format is as follows, where || denotes byte concatenation: - - FILE := VERSION || BLOCK || BLOCK ... - - BLOCK := LENGTH || DATA - - LENGTH := varint-encoded length of the subsequent data. Varint comes from - Google Protobuf, and encodes an integer into a variable number of bytes. - Each byte uses the 7 lowest bits to encode the value. The highest bit set - to 1 indicates the next byte is also part of the varint. The last byte will - have this bit set to 0. - -This file format is called the VARBLOCK format, in line with the varint format -used to denote the block sizes. - -""" - -import warnings - -from rsa._compat import byte, b - -ZERO_BYTE = b('\x00') -VARBLOCK_VERSION = 1 - -warnings.warn("The 'rsa.varblock' module was deprecated in Python-RSA version " - "3.4 due to security issues in the VARBLOCK format. See " - "https://github.com/sybrenstuvel/python-rsa/issues/13 for more information.", - DeprecationWarning) - - -def read_varint(infile): - """Reads a varint from the file. - - When the first byte to be read indicates EOF, (0, 0) is returned. When an - EOF occurs when at least one byte has been read, an EOFError exception is - raised. - - :param infile: the file-like object to read from. It should have a read() - method. - :returns: (varint, length), the read varint and the number of read bytes. - """ - - varint = 0 - read_bytes = 0 - - while True: - char = infile.read(1) - if len(char) == 0: - if read_bytes == 0: - return 0, 0 - raise EOFError('EOF while reading varint, value is %i so far' % - varint) - - byte = ord(char) - varint += (byte & 0x7F) << (7 * read_bytes) - - read_bytes += 1 - - if not byte & 0x80: - return varint, read_bytes - - -def write_varint(outfile, value): - """Writes a varint to a file. - - :param outfile: the file-like object to write to. It should have a write() - method. - :returns: the number of written bytes. - """ - - # there is a big difference between 'write the value 0' (this case) and - # 'there is nothing left to write' (the false-case of the while loop) - - if value == 0: - outfile.write(ZERO_BYTE) - return 1 - - written_bytes = 0 - while value > 0: - to_write = value & 0x7f - value >>= 7 - - if value > 0: - to_write |= 0x80 - - outfile.write(byte(to_write)) - written_bytes += 1 - - return written_bytes - - -def yield_varblocks(infile): - """Generator, yields each block in the input file. - - :param infile: file to read, is expected to have the VARBLOCK format as - described in the module's docstring. - @yields the contents of each block. - """ - - # Check the version number - first_char = infile.read(1) - if len(first_char) == 0: - raise EOFError('Unable to read VARBLOCK version number') - - version = ord(first_char) - if version != VARBLOCK_VERSION: - raise ValueError('VARBLOCK version %i not supported' % version) - - while True: - (block_size, read_bytes) = read_varint(infile) - - # EOF at block boundary, that's fine. - if read_bytes == 0 and block_size == 0: - break - - block = infile.read(block_size) - - read_size = len(block) - if read_size != block_size: - raise EOFError('Block size is %i, but could read only %i bytes' % - (block_size, read_size)) - - yield block - - -def yield_fixedblocks(infile, blocksize): - """Generator, yields each block of ``blocksize`` bytes in the input file. - - :param infile: file to read and separate in blocks. - :returns: a generator that yields the contents of each block - """ - - while True: - block = infile.read(blocksize) - - read_bytes = len(block) - if read_bytes == 0: - break - - yield block - - if read_bytes < blocksize: - break diff --git a/src/lib/websocket/ChangeLog b/src/lib/websocket/ChangeLog deleted file mode 100644 index f4483d1e..00000000 --- a/src/lib/websocket/ChangeLog +++ /dev/null @@ -1,302 +0,0 @@ -ChangeLog -============ - -- 0.47.0 - - - Fix socket constructor in _open_socket to use all relevant variables from getaddrinfo. (#383) - - .send() method is very slow (#340) - - cross-platform aync multi-client solution (#375) - - Fix detecting timeouts with SSL in recv (#387) - - Fix WebSocketApp does not poll for data correctly when using SSL (#384) - - Fix Infinite ping/pong timeouts in WebSocketApp.run_forever (#395) - - Added status message when HTTP can't be upgraded to WS (#399) - -- 0.46.0 - - - fixed OSError on windows (#370) - - fixed invalid character (#379) - -- 0.45.0 - - - change license to LGP v2.1 - - allow reuse of WebsocketApp.run_forever (#365) - - Update example for python3 (#360) - - add lock to recv function (#356) - - Parse close frame response correctly when reason present (#354) - - Fix SSL: SSLV3_ALERT_HANDSHAKE_FAILURE on Debian Stretch (#353) - - Wrap socket.gaierror with subclass of WebsocketException (#352) - - Resolve a proxy issue and a connection error (#345) - - Allow empty Host header value (#369) - - Fix undefined variable (#347) - - fix: getting a value with the key 'ca_certs' in sslopt dict (#326) - -- 0.44.0 - - -renames key in sslopt dict (#326) - -- 0.43.0 - - - Unkown kwarg 'ca_cert' when calling ssl wrap_socket() (#326) - - Race condition in WebSocket ping/pong (#327) - -- 0.42.0 - - - Implement simple cookie jar(#292) - - fix: when using pppoe redial will block.(#301) - - Fix insecure_pythons list in setup.py(#304) - - Support WEBSOCKET_CLIENT_CA_BUNDLE being directory(#307) - - WebSocketPayloadException under high traffic and limited network connection(#306) - - Not working --nocert parameter in wsdump.py(#315) - - Avoid the app to block on close on certain systems (#320) - - Fix warning is not defined. (#323) - -- 0.41.0 - - - move to repository to https://github.com/websocket-client/websocket-client.git - - _send_ping warning fails due to missing reference in _logging.__all__ (#294) - -- 0.40.0 - - Fix opcode -> op_code (#286) - -- 0.39.0 - - Shuffled around example code (#256) - - _send_ping graceful error handling (#262) - - Allow closing WebSocketApp with status/reason/timeout (#265) - - Support universal wheels (#267) - - _url: Added subnet IP address matching in no_proxy host detection (#270) - - fixed Incorrect encoding in continued messages python3 (#261) - - Pass headers for websocket handshake (#271) - - setup.py: Import `logging` before calling it. (#272) - - Implemented close code 1014 (#273) - - Support CA bundle specified by environment variable (#279) - - Response header values should not be converted to lower case (#264) - -- 0.38.0 - - Exclude port 443 from host http header (#248) - - Cleanup code (#249) - - Modify a code block directive in README (#250) - - fixed ping/pong timeouet (#253) - -- 0.37.0 - - fixed failure that `websocket.create_connection` does not accept `origin` as a parameter (#246 ) - -- 0.36.0 - - added support for using custom connection class (#235) - - use Named logger (#238) - - implement ping/pong timeout (#241) - - Corrects the syntax highlight code (#243) - - fixed failure to join thread before it is started (#242) - -- 0.35.0 - - Prints timings in console (#217) - - use inspect.getfullargspec with Python 3.x (#219) - - Check that exception message is actually a string before trying for substring check (#224) - - Use pre-initialized stream socket (#226) - - fixed TypeError: cafile, capath and cadata cannot be all omitted (#227) - -- 0.34.0 - - - Change import style (#203) - - fix attribute error on the older python. (#215) - -- 0.33.0 - - - fixed timeout+ssl error handling bug on python 2.7.10 (#190) - - add proxy support to wsdump.py (#194) - - use wsaccel if available (#193) - - add support for ssl cert chains to support client certs (#195) - - fix string formatting in exception (#196) - - fix typo in README.rst (#197) - - introduce on_data callback to pass data type. (#198) - - WebSocketBadStatusException for Handshake error (#199) - - set close timeout (#192) - - Map dict to headers list (#204) - - support client certification (#207) - - security improvement during handshake (#211) - - improve logging of error from callback (#212) - -- 0.32.0 - - - fix http proxy bug (#189) - -- 0.31.0 - - - Avoid deprecated BaseException.message (#180) - - Add travis builds (#182) - - fixed wsdump to work with piped input (#183) - - fixed output of wsdump.py with python3 (#185) - - add raw mode to wsdump.py (#186) - -- 0.30.0 - - - fixed if client is behind proxy (#169) - - support SNI for python 2.7.9+ and 3.2+ (#172) - - update Host HTTP header by user. (#171) - - fix typo for isEnabledFor (#173) - - can set verify_mode to CERT_NONE when check_hostname is enabled.(#175) - - make websockets iterable (#178) - -- 0.29.0 - - - fixed ssl socket bug - -- 0.28.0 - - - Fix erroneous argument shadowing(#168) - -- 0.27.0 - - - remove unittest2 requirements for python 2.6 (#156) - - fixed subprotocol case during header validation (#158) - - get response status and headers (#160) - - fix out-of-memory due to fragmentation when receiving a very large frame(#163) - - fix error if the payload data is nothing.(#166) - - refactoring. - -- 0.26.0 - - - all WebSocketException provide message string (#152) - - fixed tests fail when not connected to the network (#155) - - Add command line options and handle closed socket to wsdump.py (#153) - -- 0.25.0 - - - fixed for Python 2.6(#151) - -- 0.24.0 - - - Supporting http-basic auth in WebSocketApp (#143) - - fix failure of test.testInternalRecvStrict(#141) - - skip utf8 validation by skip_utf8_validation argument (#137) - - WebsocketProxyException will be raised if we got error about proxy.(#138) - -- 0.23.0 - - - Remove spurious print statement. (#135) - -- 0.22.0 - - - Fix not thread-safe of Websocket.close() (#120) - - Try to get proxy info from environment if not explicitly provided (#124) - - support proxy basic authentication. (#125) - - Fix NoneType exception at WebsocketApp.send (#126) - - not use proxy for localhost (#132) - -- 0.21.0 - - - Check for socket before attempting to close (#115) - - Enable turning off SSL verification in wsdump.py(#116) - - Enable to set subprotocol(#118) - - Better support for Autobahn test suite (http://autobahn.ws/testsuite) (#117) - -- v0.20.0 - - - fix typo. - -- v0.19.0 - - - suppress close event message(#107) - - detect socket connection state(#109) - - support for code and reason in on_close callback(#111) - - continuation frame handling seems suspicious(#113) - -- v0.18.0 - - - allow override of match_hostname usage on ssl (#105) - -- v0.17.0 - - - can't set timeout on a standing websocket connection (#102) - - fixed local variable 'error' referenced before assignment (#102, #98) - -- v0.16.0 - - - lock some method for multithread. (#92) - - disable cert verification. (#89) - -- v0.15.0 - - - fixed exception when send a large message (#84) - -- v0.14.1 - - - fixed to work on Python2.6 (#83) - -- v0.14.0 - - - Support python 3(#73) - - Support IPv6(#77) - - Support explicit web proxy(#57) - - specify cookie in connect method option(#82) - -- v0.13.0 - - - MemoryError when receiving large amount of data (~60 MB) at once(ISSUE#59) - - Controlling fragmentation(ISSUE#55) - - server certificate validation(ISSUE#56) - - PyPI tarball is missing test_websocket.py(ISSUE#65) - - Payload length encoding bug(ISSUE#58) - - disable Nagle algorithm by default(ISSUE#41) - - Better event loop in WebSocketApp(ISSUE#63) - - Skip tests that require Internet access by default(ISSUE#66) - -- v0.12.0 - - - support keep alive for WebSocketApp(ISSUE#34) - - fix some SSL bugs(ISSUE#35, #36) - - fix "Timing out leaves websocket library in bad state"(ISSUE#37) - - fix "WebSocketApp.run_with_no_err() silently eats all exceptions"(ISSUE#38) - - WebSocketTimeoutException will be raised for ws/wss timeout(ISSUE#40) - - improve wsdump message(ISSUE#42) - - support fragmentation message(ISSUE#43) - - fix some bugs - -- v0.11.0 - - - Only log non-normal close status(ISSUE#31) - - Fix default Origin isn't URI(ISSUE#32) - - fileno support(ISSUE#33) - -- v0.10.0 - - - allow to set HTTP Header to WebSocketApp(ISSUE#27) - - fix typo in pydoc(ISSUE#28) - - Passing a socketopt flag to the websocket constructor(ISSUE#29) - - websocket.send fails with long data(ISSUE#30) - - -- v0.9.0 - - - allow to set opcode in WebSocketApp.send(ISSUE#25) - - allow to modify Origin(ISSUE#26) - -- v0.8.0 - - - many bug fix - - some performance improvement - -- v0.7.0 - - - fixed problem to read long data.(ISSUE#12) - - fix buffer size boundary violation - -- v0.6.0 - - - Patches: UUID4, self.keep_running, mask_key (ISSUE#11) - - add wsdump.py tool - -- v0.5.2 - - - fix Echo App Demo Throw Error: 'NoneType' object has no attribute 'opcode (ISSUE#10) - -- v0.5.1 - - - delete invalid print statement. - -- v0.5.0 - - - support hybi-13 protocol. - -- v0.4.1 - - - fix incorrect custom header order(ISSUE#1) diff --git a/src/lib/websocket/LICENSE b/src/lib/websocket/LICENSE deleted file mode 100644 index 342ae716..00000000 --- a/src/lib/websocket/LICENSE +++ /dev/null @@ -1,135 +0,0 @@ -GNU LESSER GENERAL PUBLIC LICENSE -Version 2.1, February 1999 - -Copyright (C) 1991, 1999 Free Software Foundation, Inc. -51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -Everyone is permitted to copy and distribute verbatim copies -of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] -Preamble -The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. - -This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. - -When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. - -To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. - -For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. - -We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. - -To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. - -Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. - -Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. - -When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. - -We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. - -For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. - -In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. - -Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. - -The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. - -TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION -0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". - -A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. - -The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) - -"Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. - -Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. - -1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. - -You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. - -2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: - -a) The modified work must itself be a software library. -b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. -c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. -d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. -(For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. - -3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. - -Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. - -This option is useful when you wish to copy part of the code of the Library into a program that is not a library. - -4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. - -If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. - -5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. - -However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. - -When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. - -If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) - -Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. - -6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. - -You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: - -a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) -b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. -c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. -d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. -e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. -For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. - -It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. - -7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: - -a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. -b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. -8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. - -9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. - -10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. - -11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. - -This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. - -12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. - -13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. - -14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. - -NO WARRANTY - -15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - -16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. diff --git a/src/lib/websocket/README.rst b/src/lib/websocket/README.rst deleted file mode 100644 index 7c303983..00000000 --- a/src/lib/websocket/README.rst +++ /dev/null @@ -1,268 +0,0 @@ -================= -websocket-client -================= - -websocket-client module is WebSocket client for python. This provide the low level APIs for WebSocket. All APIs are the synchronous functions. - -websocket-client supports only hybi-13. - - -License -============ - - - LGPL - -Installation -============= - -This module is tested on Python 2.7 and Python 3.x. - -Type "python setup.py install" or "pip install websocket-client" to install. - -.. CAUTION:: - - from v0.16.0, we can install by "pip install websocket-client" for python 3. - -This module depend on - - - six - - backports.ssl_match_hostname for Python 2.x - -performance ------------------- - - "send" method is too slow on pure python. If you want to get better performace, please install numpy or wsaccel. -You can get the best performance from numpy. - - -How about Python 3 -=========================== - -Now, we support python 3 on single source code from version 0.14.0. Thanks, @battlemidget and @ralphbean. - -HTTP Proxy -============= - -Support websocket access via http proxy. -The proxy server must allow "CONNECT" method to websocket port. -Default squid setting is "ALLOWED TO CONNECT ONLY HTTPS PORT". - -Current implementation of websocket-client is using "CONNECT" method via proxy. - - -example - -.. code:: python - - import websocket - ws = websocket.WebSocket() - ws.connect("ws://example.com/websocket", http_proxy_host="proxy_host_name", http_proxy_port=3128) - - - - -Examples -======== - -Long-lived connection ---------------------- -This example is similar to how WebSocket code looks in browsers using JavaScript. - -.. code:: python - - import websocket - try: - import thread - except ImportError: - import _thread as thread - import time - - def on_message(ws, message): - print(message) - - def on_error(ws, error): - print(error) - - def on_close(ws): - print("### closed ###") - - def on_open(ws): - def run(*args): - for i in range(3): - time.sleep(1) - ws.send("Hello %d" % i) - time.sleep(1) - ws.close() - print("thread terminating...") - thread.start_new_thread(run, ()) - - - if __name__ == "__main__": - websocket.enableTrace(True) - ws = websocket.WebSocketApp("ws://echo.websocket.org/", - on_message = on_message, - on_error = on_error, - on_close = on_close) - ws.on_open = on_open - ws.run_forever() - - -Short-lived one-off send-receive --------------------------------- -This is if you want to communicate a short message and disconnect immediately when done. - -.. code:: python - - from websocket import create_connection - ws = create_connection("ws://echo.websocket.org/") - print("Sending 'Hello, World'...") - ws.send("Hello, World") - print("Sent") - print("Receiving...") - result = ws.recv() - print("Received '%s'" % result) - ws.close() - -If you want to customize socket options, set sockopt. - -sockopt example - -.. code:: python - - from websocket import create_connection - ws = create_connection("ws://echo.websocket.org/", - sockopt=((socket.IPPROTO_TCP, socket.TCP_NODELAY),)) - - -More advanced: Custom class ---------------------------- -You can also write your own class for the connection, if you want to handle the nitty-gritty details yourself. - -.. code:: python - - import socket - from websocket import create_connection, WebSocket - class MyWebSocket(WebSocket): - def recv_frame(self): - frame = super().recv_frame() - print('yay! I got this frame: ', frame) - return frame - - ws = create_connection("ws://echo.websocket.org/", - sockopt=((socket.IPPROTO_TCP, socket.TCP_NODELAY, 1),), class_=MyWebSocket) - - -FAQ -============ - -How to disable ssl cert verification? ----------------------------------------- - -Please set sslopt to {"cert_reqs": ssl.CERT_NONE}. - -WebSocketApp sample - -.. code:: python - - ws = websocket.WebSocketApp("wss://echo.websocket.org") - ws.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE}) - -create_connection sample - -.. code:: python - - ws = websocket.create_connection("wss://echo.websocket.org", - sslopt={"cert_reqs": ssl.CERT_NONE}) - -WebSocket sample - -.. code:: python - - ws = websocket.WebSocket(sslopt={"cert_reqs": ssl.CERT_NONE}) - ws.connect("wss://echo.websocket.org") - - -How to disable hostname verification. ----------------------------------------- - -Please set sslopt to {"check_hostname": False}. -(since v0.18.0) - -WebSocketApp sample - -.. code:: python - - ws = websocket.WebSocketApp("wss://echo.websocket.org") - ws.run_forever(sslopt={"check_hostname": False}) - -create_connection sample - -.. code:: python - - ws = websocket.create_connection("wss://echo.websocket.org", - sslopt={"check_hostname": False}) - -WebSocket sample - -.. code:: python - - ws = websocket.WebSocket(sslopt={"check_hostname": False}) - ws.connect("wss://echo.websocket.org") - - -How to enable `SNI `_? ---------------------------------------------------------------------------- - -SNI support is available for Python 2.7.9+ and 3.2+. It will be enabled automatically whenever possible. - - -Sub Protocols. ----------------------------------------- - -The server needs to support sub protocols, please set the subprotocol like this. - - -Subprotocol sample - -.. code:: python - - ws = websocket.create_connection("ws://example.com/websocket", subprotocols=["binary", "base64"]) - - - -wsdump.py -============ - -wsdump.py is simple WebSocket test(debug) tool. - -sample for echo.websocket.org:: - - $ wsdump.py ws://echo.websocket.org/ - Press Ctrl+C to quit - > Hello, WebSocket - < Hello, WebSocket - > How are you? - < How are you? - -Usage ---------- - -usage:: - - wsdump.py [-h] [-v [VERBOSE]] ws_url - -WebSocket Simple Dump Tool - -positional arguments: - ws_url websocket url. ex. ws://echo.websocket.org/ - -optional arguments: - -h, --help show this help message and exit -WebSocketApp - -v VERBOSE, --verbose VERBOSE set verbose mode. If set to 1, show opcode. If set to 2, enable to trace websocket module - -example:: - - $ wsdump.py ws://echo.websocket.org/ - $ wsdump.py ws://echo.websocket.org/ -v - $ wsdump.py ws://echo.websocket.org/ -vv diff --git a/src/lib/websocket/__init__.py b/src/lib/websocket/__init__.py deleted file mode 100644 index b90e65ad..00000000 --- a/src/lib/websocket/__init__.py +++ /dev/null @@ -1,29 +0,0 @@ -""" -websocket - WebSocket client library for Python - -Copyright (C) 2010 Hiroki Ohtani(liris) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1335 USA - -""" -from ._abnf import * -from ._app import WebSocketApp -from ._core import * -from ._exceptions import * -from ._logging import * -from ._socket import * - -__version__ = "0.47.0" diff --git a/src/lib/websocket/_abnf.py b/src/lib/websocket/_abnf.py deleted file mode 100644 index a0000fa1..00000000 --- a/src/lib/websocket/_abnf.py +++ /dev/null @@ -1,447 +0,0 @@ -""" -websocket - WebSocket client library for Python - -Copyright (C) 2010 Hiroki Ohtani(liris) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1335 USA - -""" -import array -import os -import struct - -import six - -from ._exceptions import * -from ._utils import validate_utf8 -from threading import Lock - -try: - if six.PY3: - import numpy - else: - numpy = None -except ImportError: - numpy = None - -try: - # If wsaccel is available we use compiled routines to mask data. - if not numpy: - from wsaccel.xormask import XorMaskerSimple - - def _mask(_m, _d): - return XorMaskerSimple(_m).process(_d) -except ImportError: - # wsaccel is not available, we rely on python implementations. - def _mask(_m, _d): - for i in range(len(_d)): - _d[i] ^= _m[i % 4] - - if six.PY3: - return _d.tobytes() - else: - return _d.tostring() - - -__all__ = [ - 'ABNF', 'continuous_frame', 'frame_buffer', - 'STATUS_NORMAL', - 'STATUS_GOING_AWAY', - 'STATUS_PROTOCOL_ERROR', - 'STATUS_UNSUPPORTED_DATA_TYPE', - 'STATUS_STATUS_NOT_AVAILABLE', - 'STATUS_ABNORMAL_CLOSED', - 'STATUS_INVALID_PAYLOAD', - 'STATUS_POLICY_VIOLATION', - 'STATUS_MESSAGE_TOO_BIG', - 'STATUS_INVALID_EXTENSION', - 'STATUS_UNEXPECTED_CONDITION', - 'STATUS_BAD_GATEWAY', - 'STATUS_TLS_HANDSHAKE_ERROR', -] - -# closing frame status codes. -STATUS_NORMAL = 1000 -STATUS_GOING_AWAY = 1001 -STATUS_PROTOCOL_ERROR = 1002 -STATUS_UNSUPPORTED_DATA_TYPE = 1003 -STATUS_STATUS_NOT_AVAILABLE = 1005 -STATUS_ABNORMAL_CLOSED = 1006 -STATUS_INVALID_PAYLOAD = 1007 -STATUS_POLICY_VIOLATION = 1008 -STATUS_MESSAGE_TOO_BIG = 1009 -STATUS_INVALID_EXTENSION = 1010 -STATUS_UNEXPECTED_CONDITION = 1011 -STATUS_BAD_GATEWAY = 1014 -STATUS_TLS_HANDSHAKE_ERROR = 1015 - -VALID_CLOSE_STATUS = ( - STATUS_NORMAL, - STATUS_GOING_AWAY, - STATUS_PROTOCOL_ERROR, - STATUS_UNSUPPORTED_DATA_TYPE, - STATUS_INVALID_PAYLOAD, - STATUS_POLICY_VIOLATION, - STATUS_MESSAGE_TOO_BIG, - STATUS_INVALID_EXTENSION, - STATUS_UNEXPECTED_CONDITION, - STATUS_BAD_GATEWAY, -) - - -class ABNF(object): - """ - ABNF frame class. - see http://tools.ietf.org/html/rfc5234 - and http://tools.ietf.org/html/rfc6455#section-5.2 - """ - - # operation code values. - OPCODE_CONT = 0x0 - OPCODE_TEXT = 0x1 - OPCODE_BINARY = 0x2 - OPCODE_CLOSE = 0x8 - OPCODE_PING = 0x9 - OPCODE_PONG = 0xa - - # available operation code value tuple - OPCODES = (OPCODE_CONT, OPCODE_TEXT, OPCODE_BINARY, OPCODE_CLOSE, - OPCODE_PING, OPCODE_PONG) - - # opcode human readable string - OPCODE_MAP = { - OPCODE_CONT: "cont", - OPCODE_TEXT: "text", - OPCODE_BINARY: "binary", - OPCODE_CLOSE: "close", - OPCODE_PING: "ping", - OPCODE_PONG: "pong" - } - - # data length threshold. - LENGTH_7 = 0x7e - LENGTH_16 = 1 << 16 - LENGTH_63 = 1 << 63 - - def __init__(self, fin=0, rsv1=0, rsv2=0, rsv3=0, - opcode=OPCODE_TEXT, mask=1, data=""): - """ - Constructor for ABNF. - please check RFC for arguments. - """ - self.fin = fin - self.rsv1 = rsv1 - self.rsv2 = rsv2 - self.rsv3 = rsv3 - self.opcode = opcode - self.mask = mask - if data is None: - data = "" - self.data = data - self.get_mask_key = os.urandom - - def validate(self, skip_utf8_validation=False): - """ - validate the ABNF frame. - skip_utf8_validation: skip utf8 validation. - """ - if self.rsv1 or self.rsv2 or self.rsv3: - raise WebSocketProtocolException("rsv is not implemented, yet") - - if self.opcode not in ABNF.OPCODES: - raise WebSocketProtocolException("Invalid opcode %r", self.opcode) - - if self.opcode == ABNF.OPCODE_PING and not self.fin: - raise WebSocketProtocolException("Invalid ping frame.") - - if self.opcode == ABNF.OPCODE_CLOSE: - l = len(self.data) - if not l: - return - if l == 1 or l >= 126: - raise WebSocketProtocolException("Invalid close frame.") - if l > 2 and not skip_utf8_validation and not validate_utf8(self.data[2:]): - raise WebSocketProtocolException("Invalid close frame.") - - code = 256 * \ - six.byte2int(self.data[0:1]) + six.byte2int(self.data[1:2]) - if not self._is_valid_close_status(code): - raise WebSocketProtocolException("Invalid close opcode.") - - @staticmethod - def _is_valid_close_status(code): - return code in VALID_CLOSE_STATUS or (3000 <= code < 5000) - - def __str__(self): - return "fin=" + str(self.fin) \ - + " opcode=" + str(self.opcode) \ - + " data=" + str(self.data) - - @staticmethod - def create_frame(data, opcode, fin=1): - """ - create frame to send text, binary and other data. - - data: data to send. This is string value(byte array). - if opcode is OPCODE_TEXT and this value is unicode, - data value is converted into unicode string, automatically. - - opcode: operation code. please see OPCODE_XXX. - - fin: fin flag. if set to 0, create continue fragmentation. - """ - if opcode == ABNF.OPCODE_TEXT and isinstance(data, six.text_type): - data = data.encode("utf-8") - # mask must be set if send data from client - return ABNF(fin, 0, 0, 0, opcode, 1, data) - - def format(self): - """ - format this object to string(byte array) to send data to server. - """ - if any(x not in (0, 1) for x in [self.fin, self.rsv1, self.rsv2, self.rsv3]): - raise ValueError("not 0 or 1") - if self.opcode not in ABNF.OPCODES: - raise ValueError("Invalid OPCODE") - length = len(self.data) - if length >= ABNF.LENGTH_63: - raise ValueError("data is too long") - - frame_header = chr(self.fin << 7 - | self.rsv1 << 6 | self.rsv2 << 5 | self.rsv3 << 4 - | self.opcode) - if length < ABNF.LENGTH_7: - frame_header += chr(self.mask << 7 | length) - frame_header = six.b(frame_header) - elif length < ABNF.LENGTH_16: - frame_header += chr(self.mask << 7 | 0x7e) - frame_header = six.b(frame_header) - frame_header += struct.pack("!H", length) - else: - frame_header += chr(self.mask << 7 | 0x7f) - frame_header = six.b(frame_header) - frame_header += struct.pack("!Q", length) - - if not self.mask: - return frame_header + self.data - else: - mask_key = self.get_mask_key(4) - return frame_header + self._get_masked(mask_key) - - def _get_masked(self, mask_key): - s = ABNF.mask(mask_key, self.data) - - if isinstance(mask_key, six.text_type): - mask_key = mask_key.encode('utf-8') - - return mask_key + s - - @staticmethod - def mask(mask_key, data): - """ - mask or unmask data. Just do xor for each byte - - mask_key: 4 byte string(byte). - - data: data to mask/unmask. - """ - if data is None: - data = "" - - if isinstance(mask_key, six.text_type): - mask_key = six.b(mask_key) - - if isinstance(data, six.text_type): - data = six.b(data) - - if numpy: - origlen = len(data) - _mask_key = mask_key[3] << 24 | mask_key[2] << 16 | mask_key[1] << 8 | mask_key[0] - - # We need data to be a multiple of four... - data += bytes(" " * (4 - (len(data) % 4)), "us-ascii") - a = numpy.frombuffer(data, dtype="uint32") - masked = numpy.bitwise_xor(a, [_mask_key]).astype("uint32") - if len(data) > origlen: - return masked.tobytes()[:origlen] - return masked.tobytes() - else: - _m = array.array("B", mask_key) - _d = array.array("B", data) - return _mask(_m, _d) - - -class frame_buffer(object): - _HEADER_MASK_INDEX = 5 - _HEADER_LENGTH_INDEX = 6 - - def __init__(self, recv_fn, skip_utf8_validation): - self.recv = recv_fn - self.skip_utf8_validation = skip_utf8_validation - # Buffers over the packets from the layer beneath until desired amount - # bytes of bytes are received. - self.recv_buffer = [] - self.clear() - self.lock = Lock() - - def clear(self): - self.header = None - self.length = None - self.mask = None - - def has_received_header(self): - return self.header is None - - def recv_header(self): - header = self.recv_strict(2) - b1 = header[0] - - if six.PY2: - b1 = ord(b1) - - fin = b1 >> 7 & 1 - rsv1 = b1 >> 6 & 1 - rsv2 = b1 >> 5 & 1 - rsv3 = b1 >> 4 & 1 - opcode = b1 & 0xf - b2 = header[1] - - if six.PY2: - b2 = ord(b2) - - has_mask = b2 >> 7 & 1 - length_bits = b2 & 0x7f - - self.header = (fin, rsv1, rsv2, rsv3, opcode, has_mask, length_bits) - - def has_mask(self): - if not self.header: - return False - return self.header[frame_buffer._HEADER_MASK_INDEX] - - def has_received_length(self): - return self.length is None - - def recv_length(self): - bits = self.header[frame_buffer._HEADER_LENGTH_INDEX] - length_bits = bits & 0x7f - if length_bits == 0x7e: - v = self.recv_strict(2) - self.length = struct.unpack("!H", v)[0] - elif length_bits == 0x7f: - v = self.recv_strict(8) - self.length = struct.unpack("!Q", v)[0] - else: - self.length = length_bits - - def has_received_mask(self): - return self.mask is None - - def recv_mask(self): - self.mask = self.recv_strict(4) if self.has_mask() else "" - - def recv_frame(self): - - with self.lock: - # Header - if self.has_received_header(): - self.recv_header() - (fin, rsv1, rsv2, rsv3, opcode, has_mask, _) = self.header - - # Frame length - if self.has_received_length(): - self.recv_length() - length = self.length - - # Mask - if self.has_received_mask(): - self.recv_mask() - mask = self.mask - - # Payload - payload = self.recv_strict(length) - if has_mask: - payload = ABNF.mask(mask, payload) - - # Reset for next frame - self.clear() - - frame = ABNF(fin, rsv1, rsv2, rsv3, opcode, has_mask, payload) - frame.validate(self.skip_utf8_validation) - - return frame - - def recv_strict(self, bufsize): - shortage = bufsize - sum(len(x) for x in self.recv_buffer) - while shortage > 0: - # Limit buffer size that we pass to socket.recv() to avoid - # fragmenting the heap -- the number of bytes recv() actually - # reads is limited by socket buffer and is relatively small, - # yet passing large numbers repeatedly causes lots of large - # buffers allocated and then shrunk, which results in - # fragmentation. - bytes_ = self.recv(min(16384, shortage)) - self.recv_buffer.append(bytes_) - shortage -= len(bytes_) - - unified = six.b("").join(self.recv_buffer) - - if shortage == 0: - self.recv_buffer = [] - return unified - else: - self.recv_buffer = [unified[bufsize:]] - return unified[:bufsize] - - -class continuous_frame(object): - - def __init__(self, fire_cont_frame, skip_utf8_validation): - self.fire_cont_frame = fire_cont_frame - self.skip_utf8_validation = skip_utf8_validation - self.cont_data = None - self.recving_frames = None - - def validate(self, frame): - if not self.recving_frames and frame.opcode == ABNF.OPCODE_CONT: - raise WebSocketProtocolException("Illegal frame") - if self.recving_frames and \ - frame.opcode in (ABNF.OPCODE_TEXT, ABNF.OPCODE_BINARY): - raise WebSocketProtocolException("Illegal frame") - - def add(self, frame): - if self.cont_data: - self.cont_data[1] += frame.data - else: - if frame.opcode in (ABNF.OPCODE_TEXT, ABNF.OPCODE_BINARY): - self.recving_frames = frame.opcode - self.cont_data = [frame.opcode, frame.data] - - if frame.fin: - self.recving_frames = None - - def is_fire(self, frame): - return frame.fin or self.fire_cont_frame - - def extract(self, frame): - data = self.cont_data - self.cont_data = None - frame.data = data[1] - if not self.fire_cont_frame and data[0] == ABNF.OPCODE_TEXT and not self.skip_utf8_validation and not validate_utf8(frame.data): - raise WebSocketPayloadException( - "cannot decode: " + repr(frame.data)) - - return [data[0], frame] diff --git a/src/lib/websocket/_app.py b/src/lib/websocket/_app.py deleted file mode 100644 index 74e90ae0..00000000 --- a/src/lib/websocket/_app.py +++ /dev/null @@ -1,320 +0,0 @@ -""" -websocket - WebSocket client library for Python - -Copyright (C) 2010 Hiroki Ohtani(liris) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1335 USA - -""" - -""" -WebSocketApp provides higher level APIs. -""" -import select -import sys -import threading -import time -import traceback - -import six - -from ._abnf import ABNF -from ._core import WebSocket, getdefaulttimeout -from ._exceptions import * -from . import _logging - - -__all__ = ["WebSocketApp"] - -class Dispatcher: - def __init__(self, app, ping_timeout): - self.app = app - self.ping_timeout = ping_timeout - - def read(self, sock, callback): - while self.app.sock.connected: - r, w, e = select.select( - (self.app.sock.sock, ), (), (), self.ping_timeout) # Use a 10 second timeout to avoid to wait forever on close - if r: - callback() - -class SSLDispacther: - def __init__(self, app, ping_timeout): - self.app = app - self.ping_timeout = ping_timeout - - def read(self, sock, callback): - while self.app.sock.connected: - r = self.select() - if r: - callback() - - def select(self): - sock = self.app.sock.sock - if sock.pending(): - return [sock,] - - r, w, e = select.select((sock, ), (), (), self.ping_timeout) - return r - -class WebSocketApp(object): - """ - Higher level of APIs are provided. - The interface is like JavaScript WebSocket object. - """ - - def __init__(self, url, header=None, - on_open=None, on_message=None, on_error=None, - on_close=None, on_ping=None, on_pong=None, - on_cont_message=None, - keep_running=True, get_mask_key=None, cookie=None, - subprotocols=None, - on_data=None): - """ - url: websocket url. - header: custom header for websocket handshake. - on_open: callable object which is called at opening websocket. - this function has one argument. The argument is this class object. - on_message: callable object which is called when received data. - on_message has 2 arguments. - The 1st argument is this class object. - The 2nd argument is utf-8 string which we get from the server. - on_error: callable object which is called when we get error. - on_error has 2 arguments. - The 1st argument is this class object. - The 2nd argument is exception object. - on_close: callable object which is called when closed the connection. - this function has one argument. The argument is this class object. - on_cont_message: callback object which is called when receive continued - frame data. - on_cont_message has 3 arguments. - The 1st argument is this class object. - The 2nd argument is utf-8 string which we get from the server. - The 3rd argument is continue flag. if 0, the data continue - to next frame data - on_data: callback object which is called when a message received. - This is called before on_message or on_cont_message, - and then on_message or on_cont_message is called. - on_data has 4 argument. - The 1st argument is this class object. - The 2nd argument is utf-8 string which we get from the server. - The 3rd argument is data type. ABNF.OPCODE_TEXT or ABNF.OPCODE_BINARY will be came. - The 4th argument is continue flag. if 0, the data continue - keep_running: this parameter is obosleted and ignored it. - get_mask_key: a callable to produce new mask keys, - see the WebSocket.set_mask_key's docstring for more information - subprotocols: array of available sub protocols. default is None. - """ - self.url = url - self.header = header if header is not None else [] - self.cookie = cookie - self.on_open = on_open - self.on_message = on_message - self.on_data = on_data - self.on_error = on_error - self.on_close = on_close - self.on_ping = on_ping - self.on_pong = on_pong - self.on_cont_message = on_cont_message - self.keep_running = False - self.get_mask_key = get_mask_key - self.sock = None - self.last_ping_tm = 0 - self.last_pong_tm = 0 - self.subprotocols = subprotocols - - def send(self, data, opcode=ABNF.OPCODE_TEXT): - """ - send message. - data: message to send. If you set opcode to OPCODE_TEXT, - data must be utf-8 string or unicode. - opcode: operation code of data. default is OPCODE_TEXT. - """ - - if not self.sock or self.sock.send(data, opcode) == 0: - raise WebSocketConnectionClosedException( - "Connection is already closed.") - - def close(self, **kwargs): - """ - close websocket connection. - """ - self.keep_running = False - if self.sock: - self.sock.close(**kwargs) - - def _send_ping(self, interval, event): - while not event.wait(interval): - self.last_ping_tm = time.time() - if self.sock: - try: - self.sock.ping() - except Exception as ex: - _logging.warning("send_ping routine terminated: {}".format(ex)) - break - - def run_forever(self, sockopt=None, sslopt=None, - ping_interval=0, ping_timeout=None, - http_proxy_host=None, http_proxy_port=None, - http_no_proxy=None, http_proxy_auth=None, - skip_utf8_validation=False, - host=None, origin=None, dispatcher=None): - """ - run event loop for WebSocket framework. - This loop is infinite loop and is alive during websocket is available. - sockopt: values for socket.setsockopt. - sockopt must be tuple - and each element is argument of sock.setsockopt. - sslopt: ssl socket optional dict. - ping_interval: automatically send "ping" command - every specified period(second) - if set to 0, not send automatically. - ping_timeout: timeout(second) if the pong message is not received. - http_proxy_host: http proxy host name. - http_proxy_port: http proxy port. If not set, set to 80. - http_no_proxy: host names, which doesn't use proxy. - skip_utf8_validation: skip utf8 validation. - host: update host header. - origin: update origin header. - """ - - if not ping_timeout or ping_timeout <= 0: - ping_timeout = None - if ping_timeout and ping_interval and ping_interval <= ping_timeout: - raise WebSocketException("Ensure ping_interval > ping_timeout") - if sockopt is None: - sockopt = [] - if sslopt is None: - sslopt = {} - if self.sock: - raise WebSocketException("socket is already opened") - thread = None - close_frame = None - self.keep_running = True - self.last_ping_tm = 0 - self.last_pong_tm = 0 - - def teardown(): - if not self.keep_running: - return - if thread and thread.isAlive(): - event.set() - thread.join() - self.keep_running = False - self.sock.close() - close_args = self._get_close_args( - close_frame.data if close_frame else None) - self._callback(self.on_close, *close_args) - self.sock = None - - try: - self.sock = WebSocket( - self.get_mask_key, sockopt=sockopt, sslopt=sslopt, - fire_cont_frame=self.on_cont_message and True or False, - skip_utf8_validation=skip_utf8_validation) - self.sock.settimeout(getdefaulttimeout()) - self.sock.connect( - self.url, header=self.header, cookie=self.cookie, - http_proxy_host=http_proxy_host, - http_proxy_port=http_proxy_port, http_no_proxy=http_no_proxy, - http_proxy_auth=http_proxy_auth, subprotocols=self.subprotocols, - host=host, origin=origin) - if not dispatcher: - dispatcher = self.create_dispatcher(ping_timeout) - - self._callback(self.on_open) - - if ping_interval: - event = threading.Event() - thread = threading.Thread( - target=self._send_ping, args=(ping_interval, event)) - thread.setDaemon(True) - thread.start() - - def read(): - if not self.keep_running: - return teardown() - - op_code, frame = self.sock.recv_data_frame(True) - if op_code == ABNF.OPCODE_CLOSE: - close_frame = frame - return teardown() - elif op_code == ABNF.OPCODE_PING: - self._callback(self.on_ping, frame.data) - elif op_code == ABNF.OPCODE_PONG: - self.last_pong_tm = time.time() - self._callback(self.on_pong, frame.data) - elif op_code == ABNF.OPCODE_CONT and self.on_cont_message: - self._callback(self.on_data, frame.data, - frame.opcode, frame.fin) - self._callback(self.on_cont_message, - frame.data, frame.fin) - else: - data = frame.data - if six.PY3 and op_code == ABNF.OPCODE_TEXT: - data = data.decode("utf-8") - self._callback(self.on_data, data, frame.opcode, True) - self._callback(self.on_message, data) - - if ping_timeout and self.last_ping_tm \ - and time.time() - self.last_ping_tm > ping_timeout \ - and self.last_ping_tm - self.last_pong_tm > ping_timeout: - raise WebSocketTimeoutException("ping/pong timed out") - return True - - dispatcher.read(self.sock.sock, read) - except (Exception, KeyboardInterrupt, SystemExit) as e: - self._callback(self.on_error, e) - if isinstance(e, SystemExit): - # propagate SystemExit further - raise - teardown() - - def create_dispatcher(self, ping_timeout): - timeout = ping_timeout or 10 - if self.sock.is_ssl(): - return SSLDispacther(self, timeout) - - return Dispatcher(self, timeout) - - def _get_close_args(self, data): - """ this functions extracts the code, reason from the close body - if they exists, and if the self.on_close except three arguments """ - import inspect - # if the on_close callback is "old", just return empty list - if sys.version_info < (3, 0): - if not self.on_close or len(inspect.getargspec(self.on_close).args) != 3: - return [] - else: - if not self.on_close or len(inspect.getfullargspec(self.on_close).args) != 3: - return [] - - if data and len(data) >= 2: - code = 256 * six.byte2int(data[0:1]) + six.byte2int(data[1:2]) - reason = data[2:].decode('utf-8') - return [code, reason] - - return [None, None] - - def _callback(self, callback, *args): - if callback: - try: - callback(self, *args) - except Exception as e: - _logging.error("error from callback {}: {}".format(callback, e)) - if _logging.isEnabledForDebug(): - _, _, tb = sys.exc_info() - traceback.print_tb(tb) diff --git a/src/lib/websocket/_cookiejar.py b/src/lib/websocket/_cookiejar.py deleted file mode 100644 index 3efeb0fd..00000000 --- a/src/lib/websocket/_cookiejar.py +++ /dev/null @@ -1,52 +0,0 @@ -try: - import Cookie -except: - import http.cookies as Cookie - - -class SimpleCookieJar(object): - def __init__(self): - self.jar = dict() - - def add(self, set_cookie): - if set_cookie: - try: - simpleCookie = Cookie.SimpleCookie(set_cookie) - except: - simpleCookie = Cookie.SimpleCookie(set_cookie.encode('ascii', 'ignore')) - - for k, v in simpleCookie.items(): - domain = v.get("domain") - if domain: - if not domain.startswith("."): - domain = "." + domain - cookie = self.jar.get(domain) if self.jar.get(domain) else Cookie.SimpleCookie() - cookie.update(simpleCookie) - self.jar[domain.lower()] = cookie - - def set(self, set_cookie): - if set_cookie: - try: - simpleCookie = Cookie.SimpleCookie(set_cookie) - except: - simpleCookie = Cookie.SimpleCookie(set_cookie.encode('ascii', 'ignore')) - - for k, v in simpleCookie.items(): - domain = v.get("domain") - if domain: - if not domain.startswith("."): - domain = "." + domain - self.jar[domain.lower()] = simpleCookie - - def get(self, host): - if not host: - return "" - - cookies = [] - for domain, simpleCookie in self.jar.items(): - host = host.lower() - if host.endswith(domain) or host == domain[1:]: - cookies.append(self.jar.get(domain)) - - return "; ".join(filter(None, ["%s=%s" % (k, v.value) for cookie in filter(None, sorted(cookies)) for k, v in - sorted(cookie.items())])) diff --git a/src/lib/websocket/_core.py b/src/lib/websocket/_core.py deleted file mode 100644 index 2d009621..00000000 --- a/src/lib/websocket/_core.py +++ /dev/null @@ -1,495 +0,0 @@ -""" -websocket - WebSocket client library for Python - -Copyright (C) 2010 Hiroki Ohtani(liris) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1335 USA - -""" -from __future__ import print_function - -import socket -import struct -import threading - -import six - -# websocket modules -from ._abnf import * -from ._exceptions import * -from ._handshake import * -from ._http import * -from ._logging import * -from ._socket import * -from ._ssl_compat import * -from ._utils import * - -__all__ = ['WebSocket', 'create_connection'] - -""" -websocket python client. -========================= - -This version support only hybi-13. -Please see http://tools.ietf.org/html/rfc6455 for protocol. -""" - - -class WebSocket(object): - """ - Low level WebSocket interface. - This class is based on - The WebSocket protocol draft-hixie-thewebsocketprotocol-76 - http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76 - - We can connect to the websocket server and send/receive data. - The following example is an echo client. - - >>> import websocket - >>> ws = websocket.WebSocket() - >>> ws.connect("ws://echo.websocket.org") - >>> ws.send("Hello, Server") - >>> ws.recv() - 'Hello, Server' - >>> ws.close() - - get_mask_key: a callable to produce new mask keys, see the set_mask_key - function's docstring for more details - sockopt: values for socket.setsockopt. - sockopt must be tuple and each element is argument of sock.setsockopt. - sslopt: dict object for ssl socket option. - fire_cont_frame: fire recv event for each cont frame. default is False - enable_multithread: if set to True, lock send method. - skip_utf8_validation: skip utf8 validation. - """ - - def __init__(self, get_mask_key=None, sockopt=None, sslopt=None, - fire_cont_frame=False, enable_multithread=False, - skip_utf8_validation=False, **_): - """ - Initialize WebSocket object. - """ - self.sock_opt = sock_opt(sockopt, sslopt) - self.handshake_response = None - self.sock = None - - self.connected = False - self.get_mask_key = get_mask_key - # These buffer over the build-up of a single frame. - self.frame_buffer = frame_buffer(self._recv, skip_utf8_validation) - self.cont_frame = continuous_frame( - fire_cont_frame, skip_utf8_validation) - - if enable_multithread: - self.lock = threading.Lock() - self.readlock = threading.Lock() - else: - self.lock = NoLock() - self.readlock = NoLock() - - def __iter__(self): - """ - Allow iteration over websocket, implying sequential `recv` executions. - """ - while True: - yield self.recv() - - def __next__(self): - return self.recv() - - def next(self): - return self.__next__() - - def fileno(self): - return self.sock.fileno() - - def set_mask_key(self, func): - """ - set function to create musk key. You can customize mask key generator. - Mainly, this is for testing purpose. - - func: callable object. the func takes 1 argument as integer. - The argument means length of mask key. - This func must return string(byte array), - which length is argument specified. - """ - self.get_mask_key = func - - def gettimeout(self): - """ - Get the websocket timeout(second). - """ - return self.sock_opt.timeout - - def settimeout(self, timeout): - """ - Set the timeout to the websocket. - - timeout: timeout time(second). - """ - self.sock_opt.timeout = timeout - if self.sock: - self.sock.settimeout(timeout) - - timeout = property(gettimeout, settimeout) - - def getsubprotocol(self): - """ - get subprotocol - """ - if self.handshake_response: - return self.handshake_response.subprotocol - else: - return None - - subprotocol = property(getsubprotocol) - - def getstatus(self): - """ - get handshake status - """ - if self.handshake_response: - return self.handshake_response.status - else: - return None - - status = property(getstatus) - - def getheaders(self): - """ - get handshake response header - """ - if self.handshake_response: - return self.handshake_response.headers - else: - return None - - def is_ssl(self): - return isinstance(self.sock, ssl.SSLSocket) - - headers = property(getheaders) - - def connect(self, url, **options): - """ - Connect to url. url is websocket url scheme. - ie. ws://host:port/resource - You can customize using 'options'. - If you set "header" list object, you can set your own custom header. - - >>> ws = WebSocket() - >>> ws.connect("ws://echo.websocket.org/", - ... header=["User-Agent: MyProgram", - ... "x-custom: header"]) - - timeout: socket timeout time. This value is integer. - if you set None for this value, - it means "use default_timeout value" - - options: "header" -> custom http header list or dict. - "cookie" -> cookie value. - "origin" -> custom origin url. - "host" -> custom host header string. - "http_proxy_host" - http proxy host name. - "http_proxy_port" - http proxy port. If not set, set to 80. - "http_no_proxy" - host names, which doesn't use proxy. - "http_proxy_auth" - http proxy auth information. - tuple of username and password. - default is None - "subprotocols" - array of available sub protocols. - default is None. - "socket" - pre-initialized stream socket. - - """ - self.sock, addrs = connect(url, self.sock_opt, proxy_info(**options), - options.pop('socket', None)) - - try: - self.handshake_response = handshake(self.sock, *addrs, **options) - self.connected = True - except: - if self.sock: - self.sock.close() - self.sock = None - raise - - def send(self, payload, opcode=ABNF.OPCODE_TEXT): - """ - Send the data as string. - - payload: Payload must be utf-8 string or unicode, - if the opcode is OPCODE_TEXT. - Otherwise, it must be string(byte array) - - opcode: operation code to send. Please see OPCODE_XXX. - """ - - frame = ABNF.create_frame(payload, opcode) - return self.send_frame(frame) - - def send_frame(self, frame): - """ - Send the data frame. - - frame: frame data created by ABNF.create_frame - - >>> ws = create_connection("ws://echo.websocket.org/") - >>> frame = ABNF.create_frame("Hello", ABNF.OPCODE_TEXT) - >>> ws.send_frame(frame) - >>> cont_frame = ABNF.create_frame("My name is ", ABNF.OPCODE_CONT, 0) - >>> ws.send_frame(frame) - >>> cont_frame = ABNF.create_frame("Foo Bar", ABNF.OPCODE_CONT, 1) - >>> ws.send_frame(frame) - - """ - if self.get_mask_key: - frame.get_mask_key = self.get_mask_key - data = frame.format() - length = len(data) - trace("send: " + repr(data)) - - with self.lock: - while data: - l = self._send(data) - data = data[l:] - - return length - - def send_binary(self, payload): - return self.send(payload, ABNF.OPCODE_BINARY) - - def ping(self, payload=""): - """ - send ping data. - - payload: data payload to send server. - """ - if isinstance(payload, six.text_type): - payload = payload.encode("utf-8") - self.send(payload, ABNF.OPCODE_PING) - - def pong(self, payload): - """ - send pong data. - - payload: data payload to send server. - """ - if isinstance(payload, six.text_type): - payload = payload.encode("utf-8") - self.send(payload, ABNF.OPCODE_PONG) - - def recv(self): - """ - Receive string data(byte array) from the server. - - return value: string(byte array) value. - """ - with self.readlock: - opcode, data = self.recv_data() - if six.PY3 and opcode == ABNF.OPCODE_TEXT: - return data.decode("utf-8") - elif opcode == ABNF.OPCODE_TEXT or opcode == ABNF.OPCODE_BINARY: - return data - else: - return '' - - def recv_data(self, control_frame=False): - """ - Receive data with operation code. - - control_frame: a boolean flag indicating whether to return control frame - data, defaults to False - - return value: tuple of operation code and string(byte array) value. - """ - opcode, frame = self.recv_data_frame(control_frame) - return opcode, frame.data - - def recv_data_frame(self, control_frame=False): - """ - Receive data with operation code. - - control_frame: a boolean flag indicating whether to return control frame - data, defaults to False - - return value: tuple of operation code and string(byte array) value. - """ - while True: - frame = self.recv_frame() - if not frame: - # handle error: - # 'NoneType' object has no attribute 'opcode' - raise WebSocketProtocolException( - "Not a valid frame %s" % frame) - elif frame.opcode in (ABNF.OPCODE_TEXT, ABNF.OPCODE_BINARY, ABNF.OPCODE_CONT): - self.cont_frame.validate(frame) - self.cont_frame.add(frame) - - if self.cont_frame.is_fire(frame): - return self.cont_frame.extract(frame) - - elif frame.opcode == ABNF.OPCODE_CLOSE: - self.send_close() - return frame.opcode, frame - elif frame.opcode == ABNF.OPCODE_PING: - if len(frame.data) < 126: - self.pong(frame.data) - else: - raise WebSocketProtocolException( - "Ping message is too long") - if control_frame: - return frame.opcode, frame - elif frame.opcode == ABNF.OPCODE_PONG: - if control_frame: - return frame.opcode, frame - - def recv_frame(self): - """ - receive data as frame from server. - - return value: ABNF frame object. - """ - return self.frame_buffer.recv_frame() - - def send_close(self, status=STATUS_NORMAL, reason=six.b("")): - """ - send close data to the server. - - status: status code to send. see STATUS_XXX. - - reason: the reason to close. This must be string or bytes. - """ - if status < 0 or status >= ABNF.LENGTH_16: - raise ValueError("code is invalid range") - self.connected = False - self.send(struct.pack('!H', status) + reason, ABNF.OPCODE_CLOSE) - - def close(self, status=STATUS_NORMAL, reason=six.b(""), timeout=3): - """ - Close Websocket object - - status: status code to send. see STATUS_XXX. - - reason: the reason to close. This must be string. - - timeout: timeout until receive a close frame. - If None, it will wait forever until receive a close frame. - """ - if self.connected: - if status < 0 or status >= ABNF.LENGTH_16: - raise ValueError("code is invalid range") - - try: - self.connected = False - self.send(struct.pack('!H', status) + - reason, ABNF.OPCODE_CLOSE) - sock_timeout = self.sock.gettimeout() - self.sock.settimeout(timeout) - try: - frame = self.recv_frame() - if isEnabledForError(): - recv_status = struct.unpack("!H", frame.data[0:2])[0] - if recv_status != STATUS_NORMAL: - error("close status: " + repr(recv_status)) - except: - pass - self.sock.settimeout(sock_timeout) - self.sock.shutdown(socket.SHUT_RDWR) - except: - pass - - self.shutdown() - - def abort(self): - """ - Low-level asynchronous abort, wakes up other threads that are waiting in recv_* - """ - if self.connected: - self.sock.shutdown(socket.SHUT_RDWR) - - def shutdown(self): - """close socket, immediately.""" - if self.sock: - self.sock.close() - self.sock = None - self.connected = False - - def _send(self, data): - return send(self.sock, data) - - def _recv(self, bufsize): - try: - return recv(self.sock, bufsize) - except WebSocketConnectionClosedException: - if self.sock: - self.sock.close() - self.sock = None - self.connected = False - raise - - -def create_connection(url, timeout=None, class_=WebSocket, **options): - """ - connect to url and return websocket object. - - Connect to url and return the WebSocket object. - Passing optional timeout parameter will set the timeout on the socket. - If no timeout is supplied, - the global default timeout setting returned by getdefauttimeout() is used. - You can customize using 'options'. - If you set "header" list object, you can set your own custom header. - - >>> conn = create_connection("ws://echo.websocket.org/", - ... header=["User-Agent: MyProgram", - ... "x-custom: header"]) - - - timeout: socket timeout time. This value is integer. - if you set None for this value, - it means "use default_timeout value" - - class_: class to instantiate when creating the connection. It has to implement - settimeout and connect. It's __init__ should be compatible with - WebSocket.__init__, i.e. accept all of it's kwargs. - options: "header" -> custom http header list or dict. - "cookie" -> cookie value. - "origin" -> custom origin url. - "host" -> custom host header string. - "http_proxy_host" - http proxy host name. - "http_proxy_port" - http proxy port. If not set, set to 80. - "http_no_proxy" - host names, which doesn't use proxy. - "http_proxy_auth" - http proxy auth information. - tuple of username and password. - default is None - "enable_multithread" -> enable lock for multithread. - "sockopt" -> socket options - "sslopt" -> ssl option - "subprotocols" - array of available sub protocols. - default is None. - "skip_utf8_validation" - skip utf8 validation. - "socket" - pre-initialized stream socket. - """ - sockopt = options.pop("sockopt", []) - sslopt = options.pop("sslopt", {}) - fire_cont_frame = options.pop("fire_cont_frame", False) - enable_multithread = options.pop("enable_multithread", False) - skip_utf8_validation = options.pop("skip_utf8_validation", False) - websock = class_(sockopt=sockopt, sslopt=sslopt, - fire_cont_frame=fire_cont_frame, - enable_multithread=enable_multithread, - skip_utf8_validation=skip_utf8_validation, **options) - websock.settimeout(timeout if timeout is not None else getdefaulttimeout()) - websock.connect(url, **options) - return websock diff --git a/src/lib/websocket/_exceptions.py b/src/lib/websocket/_exceptions.py deleted file mode 100644 index 24c85e0e..00000000 --- a/src/lib/websocket/_exceptions.py +++ /dev/null @@ -1,87 +0,0 @@ -""" -websocket - WebSocket client library for Python - -Copyright (C) 2010 Hiroki Ohtani(liris) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1335 USA - -""" - - -""" -define websocket exceptions -""" - - -class WebSocketException(Exception): - """ - websocket exception class. - """ - pass - - -class WebSocketProtocolException(WebSocketException): - """ - If the websocket protocol is invalid, this exception will be raised. - """ - pass - - -class WebSocketPayloadException(WebSocketException): - """ - If the websocket payload is invalid, this exception will be raised. - """ - pass - - -class WebSocketConnectionClosedException(WebSocketException): - """ - If remote host closed the connection or some network error happened, - this exception will be raised. - """ - pass - - -class WebSocketTimeoutException(WebSocketException): - """ - WebSocketTimeoutException will be raised at socket timeout during read/write data. - """ - pass - - -class WebSocketProxyException(WebSocketException): - """ - WebSocketProxyException will be raised when proxy error occurred. - """ - pass - - -class WebSocketBadStatusException(WebSocketException): - """ - WebSocketBadStatusException will be raised when we get bad handshake status code. - """ - - def __init__(self, message, status_code, status_message=None): - msg = message % (status_code, status_message) if status_message is not None \ - else message % status_code - super(WebSocketBadStatusException, self).__init__(msg) - self.status_code = status_code - -class WebSocketAddressException(WebSocketException): - """ - If the websocket address info cannot be found, this exception will be raised. - """ - pass diff --git a/src/lib/websocket/_handshake.py b/src/lib/websocket/_handshake.py deleted file mode 100644 index 3fd5c9ee..00000000 --- a/src/lib/websocket/_handshake.py +++ /dev/null @@ -1,180 +0,0 @@ -""" -websocket - WebSocket client library for Python - -Copyright (C) 2010 Hiroki Ohtani(liris) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1335 USA - -""" -import hashlib -import hmac -import os - -import six - -from ._cookiejar import SimpleCookieJar -from ._exceptions import * -from ._http import * -from ._logging import * -from ._socket import * - -if six.PY3: - from base64 import encodebytes as base64encode -else: - from base64 import encodestring as base64encode - -__all__ = ["handshake_response", "handshake"] - -if hasattr(hmac, "compare_digest"): - compare_digest = hmac.compare_digest -else: - def compare_digest(s1, s2): - return s1 == s2 - -# websocket supported version. -VERSION = 13 - -CookieJar = SimpleCookieJar() - - -class handshake_response(object): - - def __init__(self, status, headers, subprotocol): - self.status = status - self.headers = headers - self.subprotocol = subprotocol - CookieJar.add(headers.get("set-cookie")) - - -def handshake(sock, hostname, port, resource, **options): - headers, key = _get_handshake_headers(resource, hostname, port, options) - - header_str = "\r\n".join(headers) - send(sock, header_str) - dump("request header", header_str) - - status, resp = _get_resp_headers(sock) - success, subproto = _validate(resp, key, options.get("subprotocols")) - if not success: - raise WebSocketException("Invalid WebSocket Header") - - return handshake_response(status, resp, subproto) - -def _pack_hostname(hostname): - # IPv6 address - if ':' in hostname: - return '[' + hostname + ']' - - return hostname - -def _get_handshake_headers(resource, host, port, options): - headers = [ - "GET %s HTTP/1.1" % resource, - "Upgrade: websocket", - "Connection: Upgrade" - ] - if port == 80 or port == 443: - hostport = _pack_hostname(host) - else: - hostport = "%s:%d" % (_pack_hostname(host), port) - - if "host" in options and options["host"] is not None: - headers.append("Host: %s" % options["host"]) - else: - headers.append("Host: %s" % hostport) - - if "origin" in options and options["origin"] is not None: - headers.append("Origin: %s" % options["origin"]) - else: - headers.append("Origin: http://%s" % hostport) - - key = _create_sec_websocket_key() - headers.append("Sec-WebSocket-Key: %s" % key) - headers.append("Sec-WebSocket-Version: %s" % VERSION) - - subprotocols = options.get("subprotocols") - if subprotocols: - headers.append("Sec-WebSocket-Protocol: %s" % ",".join(subprotocols)) - - if "header" in options: - header = options["header"] - if isinstance(header, dict): - header = map(": ".join, header.items()) - headers.extend(header) - - server_cookie = CookieJar.get(host) - client_cookie = options.get("cookie", None) - - cookie = "; ".join(filter(None, [server_cookie, client_cookie])) - - if cookie: - headers.append("Cookie: %s" % cookie) - - headers.append("") - headers.append("") - - return headers, key - - -def _get_resp_headers(sock, success_status=101): - status, resp_headers, status_message = read_headers(sock) - if status != success_status: - raise WebSocketBadStatusException("Handshake status %d %s", status, status_message) - return status, resp_headers - -_HEADERS_TO_CHECK = { - "upgrade": "websocket", - "connection": "upgrade", -} - - -def _validate(headers, key, subprotocols): - subproto = None - for k, v in _HEADERS_TO_CHECK.items(): - r = headers.get(k, None) - if not r: - return False, None - r = r.lower() - if v != r: - return False, None - - if subprotocols: - subproto = headers.get("sec-websocket-protocol", None).lower() - if not subproto or subproto not in [s.lower() for s in subprotocols]: - error("Invalid subprotocol: " + str(subprotocols)) - return False, None - - result = headers.get("sec-websocket-accept", None) - if not result: - return False, None - result = result.lower() - - if isinstance(result, six.text_type): - result = result.encode('utf-8') - - value = (key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11").encode('utf-8') - hashed = base64encode(hashlib.sha1(value).digest()).strip().lower() - success = compare_digest(hashed, result) - - if success: - return True, subproto - else: - return False, None - - -def _create_sec_websocket_key(): - randomness = os.urandom(16) - return base64encode(randomness).decode('utf-8').strip() diff --git a/src/lib/websocket/_http.py b/src/lib/websocket/_http.py deleted file mode 100644 index c3b53f56..00000000 --- a/src/lib/websocket/_http.py +++ /dev/null @@ -1,256 +0,0 @@ -""" -websocket - WebSocket client library for Python - -Copyright (C) 2010 Hiroki Ohtani(liris) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1335 USA - -""" -import errno -import os -import socket -import sys - -import six - -from ._exceptions import * -from ._logging import * -from ._socket import* -from ._ssl_compat import * -from ._url import * - -if six.PY3: - from base64 import encodebytes as base64encode -else: - from base64 import encodestring as base64encode - -__all__ = ["proxy_info", "connect", "read_headers"] - - -class proxy_info(object): - - def __init__(self, **options): - self.host = options.get("http_proxy_host", None) - if self.host: - self.port = options.get("http_proxy_port", 0) - self.auth = options.get("http_proxy_auth", None) - else: - self.port = 0 - self.auth = None - self.no_proxy = options.get("http_no_proxy", None) - - -def connect(url, options, proxy, socket): - hostname, port, resource, is_secure = parse_url(url) - - if socket: - return socket, (hostname, port, resource) - - addrinfo_list, need_tunnel, auth = _get_addrinfo_list( - hostname, port, is_secure, proxy) - if not addrinfo_list: - raise WebSocketException( - "Host not found.: " + hostname + ":" + str(port)) - - sock = None - try: - sock = _open_socket(addrinfo_list, options.sockopt, options.timeout) - if need_tunnel: - sock = _tunnel(sock, hostname, port, auth) - - if is_secure: - if HAVE_SSL: - sock = _ssl_socket(sock, options.sslopt, hostname) - else: - raise WebSocketException("SSL not available.") - - return sock, (hostname, port, resource) - except: - if sock: - sock.close() - raise - - -def _get_addrinfo_list(hostname, port, is_secure, proxy): - phost, pport, pauth = get_proxy_info( - hostname, is_secure, proxy.host, proxy.port, proxy.auth, proxy.no_proxy) - try: - if not phost: - addrinfo_list = socket.getaddrinfo( - hostname, port, 0, 0, socket.SOL_TCP) - return addrinfo_list, False, None - else: - pport = pport and pport or 80 - addrinfo_list = socket.getaddrinfo(phost, pport, 0, 0, socket.SOL_TCP) - return addrinfo_list, True, pauth - except socket.gaierror as e: - raise WebSocketAddressException(e) - - -def _open_socket(addrinfo_list, sockopt, timeout): - err = None - for addrinfo in addrinfo_list: - family, socktype, proto = addrinfo[:3] - sock = socket.socket(family, socktype, proto) - sock.settimeout(timeout) - for opts in DEFAULT_SOCKET_OPTION: - sock.setsockopt(*opts) - for opts in sockopt: - sock.setsockopt(*opts) - - address = addrinfo[4] - try: - sock.connect(address) - except socket.error as error: - error.remote_ip = str(address[0]) - try: - eConnRefused = (errno.ECONNREFUSED, errno.WSAECONNREFUSED) - except: - eConnRefused = (errno.ECONNREFUSED, ) - if error.errno in eConnRefused: - err = error - continue - else: - raise - else: - break - else: - raise err - - return sock - - -def _can_use_sni(): - return six.PY2 and sys.version_info >= (2, 7, 9) or sys.version_info >= (3, 2) - - -def _wrap_sni_socket(sock, sslopt, hostname, check_hostname): - context = ssl.SSLContext(sslopt.get('ssl_version', ssl.PROTOCOL_SSLv23)) - - if sslopt.get('cert_reqs', ssl.CERT_NONE) != ssl.CERT_NONE: - context.load_verify_locations(cafile=sslopt.get('ca_certs', None), capath=sslopt.get('ca_cert_path', None)) - if sslopt.get('certfile', None): - context.load_cert_chain( - sslopt['certfile'], - sslopt.get('keyfile', None), - sslopt.get('password', None), - ) - # see - # https://github.com/liris/websocket-client/commit/b96a2e8fa765753e82eea531adb19716b52ca3ca#commitcomment-10803153 - context.verify_mode = sslopt['cert_reqs'] - if HAVE_CONTEXT_CHECK_HOSTNAME: - context.check_hostname = check_hostname - if 'ciphers' in sslopt: - context.set_ciphers(sslopt['ciphers']) - if 'cert_chain' in sslopt: - certfile, keyfile, password = sslopt['cert_chain'] - context.load_cert_chain(certfile, keyfile, password) - if 'ecdh_curve' in sslopt: - context.set_ecdh_curve(sslopt['ecdh_curve']) - - return context.wrap_socket( - sock, - do_handshake_on_connect=sslopt.get('do_handshake_on_connect', True), - suppress_ragged_eofs=sslopt.get('suppress_ragged_eofs', True), - server_hostname=hostname, - ) - - -def _ssl_socket(sock, user_sslopt, hostname): - sslopt = dict(cert_reqs=ssl.CERT_REQUIRED) - sslopt.update(user_sslopt) - - if os.environ.get('WEBSOCKET_CLIENT_CA_BUNDLE'): - certPath = os.environ.get('WEBSOCKET_CLIENT_CA_BUNDLE') - else: - certPath = os.path.join( - os.path.dirname(__file__), "cacert.pem") - if os.path.isfile(certPath) and user_sslopt.get('ca_certs', None) is None \ - and user_sslopt.get('ca_cert', None) is None: - sslopt['ca_certs'] = certPath - elif os.path.isdir(certPath) and user_sslopt.get('ca_cert_path', None) is None: - sslopt['ca_cert_path'] = certPath - - check_hostname = sslopt["cert_reqs"] != ssl.CERT_NONE and sslopt.pop( - 'check_hostname', True) - - if _can_use_sni(): - sock = _wrap_sni_socket(sock, sslopt, hostname, check_hostname) - else: - sslopt.pop('check_hostname', True) - sock = ssl.wrap_socket(sock, **sslopt) - - if not HAVE_CONTEXT_CHECK_HOSTNAME and check_hostname: - match_hostname(sock.getpeercert(), hostname) - - return sock - - -def _tunnel(sock, host, port, auth): - debug("Connecting proxy...") - connect_header = "CONNECT %s:%d HTTP/1.0\r\n" % (host, port) - # TODO: support digest auth. - if auth and auth[0]: - auth_str = auth[0] - if auth[1]: - auth_str += ":" + auth[1] - encoded_str = base64encode(auth_str.encode()).strip().decode() - connect_header += "Proxy-Authorization: Basic %s\r\n" % encoded_str - connect_header += "\r\n" - dump("request header", connect_header) - - send(sock, connect_header) - - try: - status, resp_headers, status_message = read_headers(sock) - except Exception as e: - raise WebSocketProxyException(str(e)) - - if status != 200: - raise WebSocketProxyException( - "failed CONNECT via proxy status: %r" % status) - - return sock - - -def read_headers(sock): - status = None - status_message = None - headers = {} - trace("--- response header ---") - - while True: - line = recv_line(sock) - line = line.decode('utf-8').strip() - if not line: - break - trace(line) - if not status: - - status_info = line.split(" ", 2) - status = int(status_info[1]) - status_message = status_info[2] - else: - kv = line.split(":", 1) - if len(kv) == 2: - key, value = kv - headers[key.lower()] = value.strip() - else: - raise WebSocketException("Invalid header") - - trace("-----------------------") - - return status, headers, status_message diff --git a/src/lib/websocket/_logging.py b/src/lib/websocket/_logging.py deleted file mode 100644 index d406db6a..00000000 --- a/src/lib/websocket/_logging.py +++ /dev/null @@ -1,74 +0,0 @@ -""" -websocket - WebSocket client library for Python - -Copyright (C) 2010 Hiroki Ohtani(liris) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1335 USA - -""" -import logging - -_logger = logging.getLogger('websocket') -_traceEnabled = False - -__all__ = ["enableTrace", "dump", "error", "warning", "debug", "trace", - "isEnabledForError", "isEnabledForDebug"] - - -def enableTrace(traceable): - """ - turn on/off the traceability. - - traceable: boolean value. if set True, traceability is enabled. - """ - global _traceEnabled - _traceEnabled = traceable - if traceable: - if not _logger.handlers: - _logger.addHandler(logging.StreamHandler()) - _logger.setLevel(logging.DEBUG) - - -def dump(title, message): - if _traceEnabled: - _logger.debug("--- " + title + " ---") - _logger.debug(message) - _logger.debug("-----------------------") - - -def error(msg): - _logger.error(msg) - - -def warning(msg): - _logger.warning(msg) - - -def debug(msg): - _logger.debug(msg) - - -def trace(msg): - if _traceEnabled: - _logger.debug(msg) - - -def isEnabledForError(): - return _logger.isEnabledFor(logging.ERROR) - - -def isEnabledForDebug(): - return _logger.isEnabledFor(logging.DEBUG) diff --git a/src/lib/websocket/_socket.py b/src/lib/websocket/_socket.py deleted file mode 100644 index c84fcf90..00000000 --- a/src/lib/websocket/_socket.py +++ /dev/null @@ -1,126 +0,0 @@ -""" -websocket - WebSocket client library for Python - -Copyright (C) 2010 Hiroki Ohtani(liris) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1335 USA - -""" -import socket - -import six -import sys - -from ._exceptions import * -from ._ssl_compat import * -from ._utils import * - -DEFAULT_SOCKET_OPTION = [(socket.SOL_TCP, socket.TCP_NODELAY, 1)] -if hasattr(socket, "SO_KEEPALIVE"): - DEFAULT_SOCKET_OPTION.append((socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)) -if hasattr(socket, "TCP_KEEPIDLE"): - DEFAULT_SOCKET_OPTION.append((socket.SOL_TCP, socket.TCP_KEEPIDLE, 30)) -if hasattr(socket, "TCP_KEEPINTVL"): - DEFAULT_SOCKET_OPTION.append((socket.SOL_TCP, socket.TCP_KEEPINTVL, 10)) -if hasattr(socket, "TCP_KEEPCNT"): - DEFAULT_SOCKET_OPTION.append((socket.SOL_TCP, socket.TCP_KEEPCNT, 3)) - -_default_timeout = None - -__all__ = ["DEFAULT_SOCKET_OPTION", "sock_opt", "setdefaulttimeout", "getdefaulttimeout", - "recv", "recv_line", "send"] - - -class sock_opt(object): - - def __init__(self, sockopt, sslopt): - if sockopt is None: - sockopt = [] - if sslopt is None: - sslopt = {} - self.sockopt = sockopt - self.sslopt = sslopt - self.timeout = None - - -def setdefaulttimeout(timeout): - """ - Set the global timeout setting to connect. - - timeout: default socket timeout time. This value is second. - """ - global _default_timeout - _default_timeout = timeout - - -def getdefaulttimeout(): - """ - Return the global timeout setting(second) to connect. - """ - return _default_timeout - - -def recv(sock, bufsize): - if not sock: - raise WebSocketConnectionClosedException("socket is already closed.") - - try: - bytes_ = sock.recv(bufsize) - except socket.timeout as e: - message = extract_err_message(e) - raise WebSocketTimeoutException(message) - except SSLError as e: - message = extract_err_message(e) - if isinstance(message, str) and 'timed out' in message: - raise WebSocketTimeoutException(message) - else: - raise - - if not bytes_: - raise WebSocketConnectionClosedException( - "Connection is already closed.") - - return bytes_ - - -def recv_line(sock): - line = [] - while True: - c = recv(sock, 1) - line.append(c) - if c == six.b("\n"): - break - return six.b("").join(line) - - -def send(sock, data): - if isinstance(data, six.text_type): - data = data.encode('utf-8') - - if not sock: - raise WebSocketConnectionClosedException("socket is already closed.") - - try: - return sock.send(data) - except socket.timeout as e: - message = extract_err_message(e) - raise WebSocketTimeoutException(message) - except Exception as e: - message = extract_err_message(e) - if isinstance(message, str) and "timed out" in message: - raise WebSocketTimeoutException(message) - else: - raise diff --git a/src/lib/websocket/_ssl_compat.py b/src/lib/websocket/_ssl_compat.py deleted file mode 100644 index 03048162..00000000 --- a/src/lib/websocket/_ssl_compat.py +++ /dev/null @@ -1,44 +0,0 @@ -""" -websocket - WebSocket client library for Python - -Copyright (C) 2010 Hiroki Ohtani(liris) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1335 USA - -""" -__all__ = ["HAVE_SSL", "ssl", "SSLError"] - -try: - import ssl - from ssl import SSLError - if hasattr(ssl, 'SSLContext') and hasattr(ssl.SSLContext, 'check_hostname'): - HAVE_CONTEXT_CHECK_HOSTNAME = True - else: - HAVE_CONTEXT_CHECK_HOSTNAME = False - if hasattr(ssl, "match_hostname"): - from ssl import match_hostname - else: - from backports.ssl_match_hostname import match_hostname - __all__.append("match_hostname") - __all__.append("HAVE_CONTEXT_CHECK_HOSTNAME") - - HAVE_SSL = True -except ImportError: - # dummy class of SSLError for ssl none-support environment. - class SSLError(Exception): - pass - - HAVE_SSL = False diff --git a/src/lib/websocket/_url.py b/src/lib/websocket/_url.py deleted file mode 100644 index f7bdf346..00000000 --- a/src/lib/websocket/_url.py +++ /dev/null @@ -1,160 +0,0 @@ -""" -websocket - WebSocket client library for Python - -Copyright (C) 2010 Hiroki Ohtani(liris) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1335 USA - -""" - -import os -import socket -import struct - -from six.moves.urllib.parse import urlparse - - -__all__ = ["parse_url", "get_proxy_info"] - - -def parse_url(url): - """ - parse url and the result is tuple of - (hostname, port, resource path and the flag of secure mode) - - url: url string. - """ - if ":" not in url: - raise ValueError("url is invalid") - - scheme, url = url.split(":", 1) - - parsed = urlparse(url, scheme="ws") - if parsed.hostname: - hostname = parsed.hostname - else: - raise ValueError("hostname is invalid") - port = 0 - if parsed.port: - port = parsed.port - - is_secure = False - if scheme == "ws": - if not port: - port = 80 - elif scheme == "wss": - is_secure = True - if not port: - port = 443 - else: - raise ValueError("scheme %s is invalid" % scheme) - - if parsed.path: - resource = parsed.path - else: - resource = "/" - - if parsed.query: - resource += "?" + parsed.query - - return hostname, port, resource, is_secure - - -DEFAULT_NO_PROXY_HOST = ["localhost", "127.0.0.1"] - - -def _is_ip_address(addr): - try: - socket.inet_aton(addr) - except socket.error: - return False - else: - return True - - -def _is_subnet_address(hostname): - try: - addr, netmask = hostname.split("/") - return _is_ip_address(addr) and 0 <= int(netmask) < 32 - except ValueError: - return False - - -def _is_address_in_network(ip, net): - ipaddr = struct.unpack('I', socket.inet_aton(ip))[0] - netaddr, bits = net.split('/') - netmask = struct.unpack('I', socket.inet_aton(netaddr))[0] & ((2 << int(bits) - 1) - 1) - return ipaddr & netmask == netmask - - -def _is_no_proxy_host(hostname, no_proxy): - if not no_proxy: - v = os.environ.get("no_proxy", "").replace(" ", "") - no_proxy = v.split(",") - if not no_proxy: - no_proxy = DEFAULT_NO_PROXY_HOST - - if hostname in no_proxy: - return True - elif _is_ip_address(hostname): - return any([_is_address_in_network(hostname, subnet) for subnet in no_proxy if _is_subnet_address(subnet)]) - - return False - - -def get_proxy_info( - hostname, is_secure, proxy_host=None, proxy_port=0, proxy_auth=None, - no_proxy=None): - """ - try to retrieve proxy host and port from environment - if not provided in options. - result is (proxy_host, proxy_port, proxy_auth). - proxy_auth is tuple of username and password - of proxy authentication information. - - hostname: websocket server name. - - is_secure: is the connection secure? (wss) - looks for "https_proxy" in env - before falling back to "http_proxy" - - options: "http_proxy_host" - http proxy host name. - "http_proxy_port" - http proxy port. - "http_no_proxy" - host names, which doesn't use proxy. - "http_proxy_auth" - http proxy auth information. - tuple of username and password. - default is None - """ - if _is_no_proxy_host(hostname, no_proxy): - return None, 0, None - - if proxy_host: - port = proxy_port - auth = proxy_auth - return proxy_host, port, auth - - env_keys = ["http_proxy"] - if is_secure: - env_keys.insert(0, "https_proxy") - - for key in env_keys: - value = os.environ.get(key, None) - if value: - proxy = urlparse(value) - auth = (proxy.username, proxy.password) if proxy.username else None - return proxy.hostname, proxy.port, auth - - return None, 0, None diff --git a/src/lib/websocket/_utils.py b/src/lib/websocket/_utils.py deleted file mode 100644 index 399fb89d..00000000 --- a/src/lib/websocket/_utils.py +++ /dev/null @@ -1,105 +0,0 @@ -""" -websocket - WebSocket client library for Python - -Copyright (C) 2010 Hiroki Ohtani(liris) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1335 USA - -""" -import six - -__all__ = ["NoLock", "validate_utf8", "extract_err_message"] - - -class NoLock(object): - - def __enter__(self): - pass - - def __exit__(self, exc_type, exc_value, traceback): - pass - -try: - # If wsaccel is available we use compiled routines to validate UTF-8 - # strings. - from wsaccel.utf8validator import Utf8Validator - - def _validate_utf8(utfbytes): - return Utf8Validator().validate(utfbytes)[0] - -except ImportError: - # UTF-8 validator - # python implementation of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ - - _UTF8_ACCEPT = 0 - _UTF8_REJECT = 12 - - _UTF8D = [ - # The first part of the table maps bytes to character classes that - # to reduce the size of the transition table and create bitmasks. - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8, - - # The second part is a transition table that maps a combination - # of a state of the automaton and a character class to a state. - 0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12, - 12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12, - 12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12, - 12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12, - 12,36,12,12,12,12,12,12,12,12,12,12, ] - - def _decode(state, codep, ch): - tp = _UTF8D[ch] - - codep = (ch & 0x3f) | (codep << 6) if ( - state != _UTF8_ACCEPT) else (0xff >> tp) & ch - state = _UTF8D[256 + state + tp] - - return state, codep - - def _validate_utf8(utfbytes): - state = _UTF8_ACCEPT - codep = 0 - for i in utfbytes: - if six.PY2: - i = ord(i) - state, codep = _decode(state, codep, i) - if state == _UTF8_REJECT: - return False - - return True - - -def validate_utf8(utfbytes): - """ - validate utf8 byte string. - utfbytes: utf byte string to check. - return value: if valid utf8 string, return true. Otherwise, return false. - """ - return _validate_utf8(utfbytes) - - -def extract_err_message(exception): - if exception.args: - return exception.args[0] - else: - return None diff --git a/src/lib/win_inet_pton/__init__.py b/src/lib/win_inet_pton/__init__.py deleted file mode 100644 index 12aaf46c..00000000 --- a/src/lib/win_inet_pton/__init__.py +++ /dev/null @@ -1,84 +0,0 @@ -# This software released into the public domain. Anyone is free to copy, -# modify, publish, use, compile, sell, or distribute this software, -# either in source code form or as a compiled binary, for any purpose, -# commercial or non-commercial, and by any means. - -import socket -import ctypes -import os - - -class sockaddr(ctypes.Structure): - _fields_ = [("sa_family", ctypes.c_short), - ("__pad1", ctypes.c_ushort), - ("ipv4_addr", ctypes.c_byte * 4), - ("ipv6_addr", ctypes.c_byte * 16), - ("__pad2", ctypes.c_ulong)] - -if hasattr(ctypes, 'windll'): - WSAStringToAddressA = ctypes.windll.ws2_32.WSAStringToAddressA - WSAAddressToStringA = ctypes.windll.ws2_32.WSAAddressToStringA -else: - def not_windows(): - raise SystemError( - "Invalid platform. ctypes.windll must be available." - ) - WSAStringToAddressA = not_windows - WSAAddressToStringA = not_windows - - -def inet_pton(address_family, ip_string): - addr = sockaddr() - addr.sa_family = address_family - addr_size = ctypes.c_int(ctypes.sizeof(addr)) - - if WSAStringToAddressA( - ip_string, - address_family, - None, - ctypes.byref(addr), - ctypes.byref(addr_size) - ) != 0: - raise socket.error(ctypes.FormatError()) - - if address_family == socket.AF_INET: - return ctypes.string_at(addr.ipv4_addr, 4) - if address_family == socket.AF_INET6: - return ctypes.string_at(addr.ipv6_addr, 16) - - raise socket.error('unknown address family') - - -def inet_ntop(address_family, packed_ip): - addr = sockaddr() - addr.sa_family = address_family - addr_size = ctypes.c_int(ctypes.sizeof(addr)) - ip_string = ctypes.create_string_buffer(128) - ip_string_size = ctypes.c_int(ctypes.sizeof(ip_string)) - - if address_family == socket.AF_INET: - if len(packed_ip) != ctypes.sizeof(addr.ipv4_addr): - raise socket.error('packed IP wrong length for inet_ntoa') - ctypes.memmove(addr.ipv4_addr, packed_ip, 4) - elif address_family == socket.AF_INET6: - if len(packed_ip) != ctypes.sizeof(addr.ipv6_addr): - raise socket.error('packed IP wrong length for inet_ntoa') - ctypes.memmove(addr.ipv6_addr, packed_ip, 16) - else: - raise socket.error('unknown address family') - - if WSAAddressToStringA( - ctypes.byref(addr), - addr_size, - None, - ip_string, - ctypes.byref(ip_string_size) - ) != 0: - raise socket.error(ctypes.FormatError()) - - return ip_string[:ip_string_size.value - 1] - -# Adding our two functions to the socket library -if os.name == 'nt': - socket.inet_pton = inet_pton - socket.inet_ntop = inet_ntop