faset over fra Z3950 til google books
This commit is contained in:
31
python/gdata/tlslite/utils/AES.py
Normal file
31
python/gdata/tlslite/utils/AES.py
Normal file
@@ -0,0 +1,31 @@
|
||||
"""Abstract class for AES."""
|
||||
|
||||
class AES:
|
||||
def __init__(self, key, mode, IV, implementation):
|
||||
if len(key) not in (16, 24, 32):
|
||||
raise AssertionError()
|
||||
if mode != 2:
|
||||
raise AssertionError()
|
||||
if len(IV) != 16:
|
||||
raise AssertionError()
|
||||
self.isBlockCipher = True
|
||||
self.block_size = 16
|
||||
self.implementation = implementation
|
||||
if len(key)==16:
|
||||
self.name = "aes128"
|
||||
elif len(key)==24:
|
||||
self.name = "aes192"
|
||||
elif len(key)==32:
|
||||
self.name = "aes256"
|
||||
else:
|
||||
raise AssertionError()
|
||||
|
||||
#CBC-Mode encryption, returns ciphertext
|
||||
#WARNING: *MAY* modify the input as well
|
||||
def encrypt(self, plaintext):
|
||||
assert(len(plaintext) % 16 == 0)
|
||||
|
||||
#CBC-Mode decryption, returns plaintext
|
||||
#WARNING: *MAY* modify the input as well
|
||||
def decrypt(self, ciphertext):
|
||||
assert(len(ciphertext) % 16 == 0)
|
34
python/gdata/tlslite/utils/ASN1Parser.py
Normal file
34
python/gdata/tlslite/utils/ASN1Parser.py
Normal file
@@ -0,0 +1,34 @@
|
||||
"""Class for parsing ASN.1"""
|
||||
from compat import *
|
||||
from codec import *
|
||||
|
||||
#Takes a byte array which has a DER TLV field at its head
|
||||
class ASN1Parser:
|
||||
def __init__(self, bytes):
|
||||
p = Parser(bytes)
|
||||
p.get(1) #skip Type
|
||||
|
||||
#Get Length
|
||||
self.length = self._getASN1Length(p)
|
||||
|
||||
#Get Value
|
||||
self.value = p.getFixBytes(self.length)
|
||||
|
||||
#Assuming this is a sequence...
|
||||
def getChild(self, which):
|
||||
p = Parser(self.value)
|
||||
for x in range(which+1):
|
||||
markIndex = p.index
|
||||
p.get(1) #skip Type
|
||||
length = self._getASN1Length(p)
|
||||
p.getFixBytes(length)
|
||||
return ASN1Parser(p.bytes[markIndex : p.index])
|
||||
|
||||
#Decode the ASN.1 DER length field
|
||||
def _getASN1Length(self, p):
|
||||
firstLength = p.get(1)
|
||||
if firstLength<=127:
|
||||
return firstLength
|
||||
else:
|
||||
lengthLength = firstLength & 0x7F
|
||||
return p.get(lengthLength)
|
34
python/gdata/tlslite/utils/Cryptlib_AES.py
Normal file
34
python/gdata/tlslite/utils/Cryptlib_AES.py
Normal file
@@ -0,0 +1,34 @@
|
||||
"""Cryptlib AES implementation."""
|
||||
|
||||
from cryptomath import *
|
||||
from AES import *
|
||||
|
||||
if cryptlibpyLoaded:
|
||||
|
||||
def new(key, mode, IV):
|
||||
return Cryptlib_AES(key, mode, IV)
|
||||
|
||||
class Cryptlib_AES(AES):
|
||||
|
||||
def __init__(self, key, mode, IV):
|
||||
AES.__init__(self, key, mode, IV, "cryptlib")
|
||||
self.context = cryptlib_py.cryptCreateContext(cryptlib_py.CRYPT_UNUSED, cryptlib_py.CRYPT_ALGO_AES)
|
||||
cryptlib_py.cryptSetAttribute(self.context, cryptlib_py.CRYPT_CTXINFO_MODE, cryptlib_py.CRYPT_MODE_CBC)
|
||||
cryptlib_py.cryptSetAttribute(self.context, cryptlib_py.CRYPT_CTXINFO_KEYSIZE, len(key))
|
||||
cryptlib_py.cryptSetAttributeString(self.context, cryptlib_py.CRYPT_CTXINFO_KEY, key)
|
||||
cryptlib_py.cryptSetAttributeString(self.context, cryptlib_py.CRYPT_CTXINFO_IV, IV)
|
||||
|
||||
def __del__(self):
|
||||
cryptlib_py.cryptDestroyContext(self.context)
|
||||
|
||||
def encrypt(self, plaintext):
|
||||
AES.encrypt(self, plaintext)
|
||||
bytes = stringToBytes(plaintext)
|
||||
cryptlib_py.cryptEncrypt(self.context, bytes)
|
||||
return bytesToString(bytes)
|
||||
|
||||
def decrypt(self, ciphertext):
|
||||
AES.decrypt(self, ciphertext)
|
||||
bytes = stringToBytes(ciphertext)
|
||||
cryptlib_py.cryptDecrypt(self.context, bytes)
|
||||
return bytesToString(bytes)
|
28
python/gdata/tlslite/utils/Cryptlib_RC4.py
Normal file
28
python/gdata/tlslite/utils/Cryptlib_RC4.py
Normal file
@@ -0,0 +1,28 @@
|
||||
"""Cryptlib RC4 implementation."""
|
||||
|
||||
from cryptomath import *
|
||||
from RC4 import RC4
|
||||
|
||||
if cryptlibpyLoaded:
|
||||
|
||||
def new(key):
|
||||
return Cryptlib_RC4(key)
|
||||
|
||||
class Cryptlib_RC4(RC4):
|
||||
|
||||
def __init__(self, key):
|
||||
RC4.__init__(self, key, "cryptlib")
|
||||
self.context = cryptlib_py.cryptCreateContext(cryptlib_py.CRYPT_UNUSED, cryptlib_py.CRYPT_ALGO_RC4)
|
||||
cryptlib_py.cryptSetAttribute(self.context, cryptlib_py.CRYPT_CTXINFO_KEYSIZE, len(key))
|
||||
cryptlib_py.cryptSetAttributeString(self.context, cryptlib_py.CRYPT_CTXINFO_KEY, key)
|
||||
|
||||
def __del__(self):
|
||||
cryptlib_py.cryptDestroyContext(self.context)
|
||||
|
||||
def encrypt(self, plaintext):
|
||||
bytes = stringToBytes(plaintext)
|
||||
cryptlib_py.cryptEncrypt(self.context, bytes)
|
||||
return bytesToString(bytes)
|
||||
|
||||
def decrypt(self, ciphertext):
|
||||
return self.encrypt(ciphertext)
|
35
python/gdata/tlslite/utils/Cryptlib_TripleDES.py
Normal file
35
python/gdata/tlslite/utils/Cryptlib_TripleDES.py
Normal file
@@ -0,0 +1,35 @@
|
||||
"""Cryptlib 3DES implementation."""
|
||||
|
||||
from cryptomath import *
|
||||
|
||||
from TripleDES import *
|
||||
|
||||
if cryptlibpyLoaded:
|
||||
|
||||
def new(key, mode, IV):
|
||||
return Cryptlib_TripleDES(key, mode, IV)
|
||||
|
||||
class Cryptlib_TripleDES(TripleDES):
|
||||
|
||||
def __init__(self, key, mode, IV):
|
||||
TripleDES.__init__(self, key, mode, IV, "cryptlib")
|
||||
self.context = cryptlib_py.cryptCreateContext(cryptlib_py.CRYPT_UNUSED, cryptlib_py.CRYPT_ALGO_3DES)
|
||||
cryptlib_py.cryptSetAttribute(self.context, cryptlib_py.CRYPT_CTXINFO_MODE, cryptlib_py.CRYPT_MODE_CBC)
|
||||
cryptlib_py.cryptSetAttribute(self.context, cryptlib_py.CRYPT_CTXINFO_KEYSIZE, len(key))
|
||||
cryptlib_py.cryptSetAttributeString(self.context, cryptlib_py.CRYPT_CTXINFO_KEY, key)
|
||||
cryptlib_py.cryptSetAttributeString(self.context, cryptlib_py.CRYPT_CTXINFO_IV, IV)
|
||||
|
||||
def __del__(self):
|
||||
cryptlib_py.cryptDestroyContext(self.context)
|
||||
|
||||
def encrypt(self, plaintext):
|
||||
TripleDES.encrypt(self, plaintext)
|
||||
bytes = stringToBytes(plaintext)
|
||||
cryptlib_py.cryptEncrypt(self.context, bytes)
|
||||
return bytesToString(bytes)
|
||||
|
||||
def decrypt(self, ciphertext):
|
||||
TripleDES.decrypt(self, ciphertext)
|
||||
bytes = stringToBytes(ciphertext)
|
||||
cryptlib_py.cryptDecrypt(self.context, bytes)
|
||||
return bytesToString(bytes)
|
49
python/gdata/tlslite/utils/OpenSSL_AES.py
Normal file
49
python/gdata/tlslite/utils/OpenSSL_AES.py
Normal file
@@ -0,0 +1,49 @@
|
||||
"""OpenSSL/M2Crypto AES implementation."""
|
||||
|
||||
from cryptomath import *
|
||||
from AES import *
|
||||
|
||||
if m2cryptoLoaded:
|
||||
|
||||
def new(key, mode, IV):
|
||||
return OpenSSL_AES(key, mode, IV)
|
||||
|
||||
class OpenSSL_AES(AES):
|
||||
|
||||
def __init__(self, key, mode, IV):
|
||||
AES.__init__(self, key, mode, IV, "openssl")
|
||||
self.key = key
|
||||
self.IV = IV
|
||||
|
||||
def _createContext(self, encrypt):
|
||||
context = m2.cipher_ctx_new()
|
||||
if len(self.key)==16:
|
||||
cipherType = m2.aes_128_cbc()
|
||||
if len(self.key)==24:
|
||||
cipherType = m2.aes_192_cbc()
|
||||
if len(self.key)==32:
|
||||
cipherType = m2.aes_256_cbc()
|
||||
m2.cipher_init(context, cipherType, self.key, self.IV, encrypt)
|
||||
return context
|
||||
|
||||
def encrypt(self, plaintext):
|
||||
AES.encrypt(self, plaintext)
|
||||
context = self._createContext(1)
|
||||
ciphertext = m2.cipher_update(context, plaintext)
|
||||
m2.cipher_ctx_free(context)
|
||||
self.IV = ciphertext[-self.block_size:]
|
||||
return ciphertext
|
||||
|
||||
def decrypt(self, ciphertext):
|
||||
AES.decrypt(self, ciphertext)
|
||||
context = self._createContext(0)
|
||||
#I think M2Crypto has a bug - it fails to decrypt and return the last block passed in.
|
||||
#To work around this, we append sixteen zeros to the string, below:
|
||||
plaintext = m2.cipher_update(context, ciphertext+('\0'*16))
|
||||
|
||||
#If this bug is ever fixed, then plaintext will end up having a garbage
|
||||
#plaintext block on the end. That's okay - the below code will discard it.
|
||||
plaintext = plaintext[:len(ciphertext)]
|
||||
m2.cipher_ctx_free(context)
|
||||
self.IV = ciphertext[-self.block_size:]
|
||||
return plaintext
|
25
python/gdata/tlslite/utils/OpenSSL_RC4.py
Normal file
25
python/gdata/tlslite/utils/OpenSSL_RC4.py
Normal file
@@ -0,0 +1,25 @@
|
||||
"""OpenSSL/M2Crypto RC4 implementation."""
|
||||
|
||||
from cryptomath import *
|
||||
from RC4 import RC4
|
||||
|
||||
if m2cryptoLoaded:
|
||||
|
||||
def new(key):
|
||||
return OpenSSL_RC4(key)
|
||||
|
||||
class OpenSSL_RC4(RC4):
|
||||
|
||||
def __init__(self, key):
|
||||
RC4.__init__(self, key, "openssl")
|
||||
self.rc4 = m2.rc4_new()
|
||||
m2.rc4_set_key(self.rc4, key)
|
||||
|
||||
def __del__(self):
|
||||
m2.rc4_free(self.rc4)
|
||||
|
||||
def encrypt(self, plaintext):
|
||||
return m2.rc4_update(self.rc4, plaintext)
|
||||
|
||||
def decrypt(self, ciphertext):
|
||||
return self.encrypt(ciphertext)
|
148
python/gdata/tlslite/utils/OpenSSL_RSAKey.py
Normal file
148
python/gdata/tlslite/utils/OpenSSL_RSAKey.py
Normal file
@@ -0,0 +1,148 @@
|
||||
"""OpenSSL/M2Crypto RSA implementation."""
|
||||
|
||||
from cryptomath import *
|
||||
|
||||
from RSAKey import *
|
||||
from Python_RSAKey import Python_RSAKey
|
||||
|
||||
#copied from M2Crypto.util.py, so when we load the local copy of m2
|
||||
#we can still use it
|
||||
def password_callback(v, prompt1='Enter private key passphrase:',
|
||||
prompt2='Verify passphrase:'):
|
||||
from getpass import getpass
|
||||
while 1:
|
||||
try:
|
||||
p1=getpass(prompt1)
|
||||
if v:
|
||||
p2=getpass(prompt2)
|
||||
if p1==p2:
|
||||
break
|
||||
else:
|
||||
break
|
||||
except KeyboardInterrupt:
|
||||
return None
|
||||
return p1
|
||||
|
||||
|
||||
if m2cryptoLoaded:
|
||||
class OpenSSL_RSAKey(RSAKey):
|
||||
def __init__(self, n=0, e=0):
|
||||
self.rsa = None
|
||||
self._hasPrivateKey = False
|
||||
if (n and not e) or (e and not n):
|
||||
raise AssertionError()
|
||||
if n and e:
|
||||
self.rsa = m2.rsa_new()
|
||||
m2.rsa_set_n(self.rsa, numberToMPI(n))
|
||||
m2.rsa_set_e(self.rsa, numberToMPI(e))
|
||||
|
||||
def __del__(self):
|
||||
if self.rsa:
|
||||
m2.rsa_free(self.rsa)
|
||||
|
||||
def __getattr__(self, name):
|
||||
if name == 'e':
|
||||
if not self.rsa:
|
||||
return 0
|
||||
return mpiToNumber(m2.rsa_get_e(self.rsa))
|
||||
elif name == 'n':
|
||||
if not self.rsa:
|
||||
return 0
|
||||
return mpiToNumber(m2.rsa_get_n(self.rsa))
|
||||
else:
|
||||
raise AttributeError
|
||||
|
||||
def hasPrivateKey(self):
|
||||
return self._hasPrivateKey
|
||||
|
||||
def hash(self):
|
||||
return Python_RSAKey(self.n, self.e).hash()
|
||||
|
||||
def _rawPrivateKeyOp(self, m):
|
||||
s = numberToString(m)
|
||||
byteLength = numBytes(self.n)
|
||||
if len(s)== byteLength:
|
||||
pass
|
||||
elif len(s) == byteLength-1:
|
||||
s = '\0' + s
|
||||
else:
|
||||
raise AssertionError()
|
||||
c = stringToNumber(m2.rsa_private_encrypt(self.rsa, s,
|
||||
m2.no_padding))
|
||||
return c
|
||||
|
||||
def _rawPublicKeyOp(self, c):
|
||||
s = numberToString(c)
|
||||
byteLength = numBytes(self.n)
|
||||
if len(s)== byteLength:
|
||||
pass
|
||||
elif len(s) == byteLength-1:
|
||||
s = '\0' + s
|
||||
else:
|
||||
raise AssertionError()
|
||||
m = stringToNumber(m2.rsa_public_decrypt(self.rsa, s,
|
||||
m2.no_padding))
|
||||
return m
|
||||
|
||||
def acceptsPassword(self): return True
|
||||
|
||||
def write(self, password=None):
|
||||
bio = m2.bio_new(m2.bio_s_mem())
|
||||
if self._hasPrivateKey:
|
||||
if password:
|
||||
def f(v): return password
|
||||
m2.rsa_write_key(self.rsa, bio, m2.des_ede_cbc(), f)
|
||||
else:
|
||||
def f(): pass
|
||||
m2.rsa_write_key_no_cipher(self.rsa, bio, f)
|
||||
else:
|
||||
if password:
|
||||
raise AssertionError()
|
||||
m2.rsa_write_pub_key(self.rsa, bio)
|
||||
s = m2.bio_read(bio, m2.bio_ctrl_pending(bio))
|
||||
m2.bio_free(bio)
|
||||
return s
|
||||
|
||||
def writeXMLPublicKey(self, indent=''):
|
||||
return Python_RSAKey(self.n, self.e).write(indent)
|
||||
|
||||
def generate(bits):
|
||||
key = OpenSSL_RSAKey()
|
||||
def f():pass
|
||||
key.rsa = m2.rsa_generate_key(bits, 3, f)
|
||||
key._hasPrivateKey = True
|
||||
return key
|
||||
generate = staticmethod(generate)
|
||||
|
||||
def parse(s, passwordCallback=None):
|
||||
if s.startswith("-----BEGIN "):
|
||||
if passwordCallback==None:
|
||||
callback = password_callback
|
||||
else:
|
||||
def f(v, prompt1=None, prompt2=None):
|
||||
return passwordCallback()
|
||||
callback = f
|
||||
bio = m2.bio_new(m2.bio_s_mem())
|
||||
try:
|
||||
m2.bio_write(bio, s)
|
||||
key = OpenSSL_RSAKey()
|
||||
if s.startswith("-----BEGIN RSA PRIVATE KEY-----"):
|
||||
def f():pass
|
||||
key.rsa = m2.rsa_read_key(bio, callback)
|
||||
if key.rsa == None:
|
||||
raise SyntaxError()
|
||||
key._hasPrivateKey = True
|
||||
elif s.startswith("-----BEGIN PUBLIC KEY-----"):
|
||||
key.rsa = m2.rsa_read_pub_key(bio)
|
||||
if key.rsa == None:
|
||||
raise SyntaxError()
|
||||
key._hasPrivateKey = False
|
||||
else:
|
||||
raise SyntaxError()
|
||||
return key
|
||||
finally:
|
||||
m2.bio_free(bio)
|
||||
else:
|
||||
raise SyntaxError()
|
||||
|
||||
parse = staticmethod(parse)
|
44
python/gdata/tlslite/utils/OpenSSL_TripleDES.py
Normal file
44
python/gdata/tlslite/utils/OpenSSL_TripleDES.py
Normal file
@@ -0,0 +1,44 @@
|
||||
"""OpenSSL/M2Crypto 3DES implementation."""
|
||||
|
||||
from cryptomath import *
|
||||
from TripleDES import *
|
||||
|
||||
if m2cryptoLoaded:
|
||||
|
||||
def new(key, mode, IV):
|
||||
return OpenSSL_TripleDES(key, mode, IV)
|
||||
|
||||
class OpenSSL_TripleDES(TripleDES):
|
||||
|
||||
def __init__(self, key, mode, IV):
|
||||
TripleDES.__init__(self, key, mode, IV, "openssl")
|
||||
self.key = key
|
||||
self.IV = IV
|
||||
|
||||
def _createContext(self, encrypt):
|
||||
context = m2.cipher_ctx_new()
|
||||
cipherType = m2.des_ede3_cbc()
|
||||
m2.cipher_init(context, cipherType, self.key, self.IV, encrypt)
|
||||
return context
|
||||
|
||||
def encrypt(self, plaintext):
|
||||
TripleDES.encrypt(self, plaintext)
|
||||
context = self._createContext(1)
|
||||
ciphertext = m2.cipher_update(context, plaintext)
|
||||
m2.cipher_ctx_free(context)
|
||||
self.IV = ciphertext[-self.block_size:]
|
||||
return ciphertext
|
||||
|
||||
def decrypt(self, ciphertext):
|
||||
TripleDES.decrypt(self, ciphertext)
|
||||
context = self._createContext(0)
|
||||
#I think M2Crypto has a bug - it fails to decrypt and return the last block passed in.
|
||||
#To work around this, we append sixteen zeros to the string, below:
|
||||
plaintext = m2.cipher_update(context, ciphertext+('\0'*16))
|
||||
|
||||
#If this bug is ever fixed, then plaintext will end up having a garbage
|
||||
#plaintext block on the end. That's okay - the below code will ignore it.
|
||||
plaintext = plaintext[:len(ciphertext)]
|
||||
m2.cipher_ctx_free(context)
|
||||
self.IV = ciphertext[-self.block_size:]
|
||||
return plaintext
|
22
python/gdata/tlslite/utils/PyCrypto_AES.py
Normal file
22
python/gdata/tlslite/utils/PyCrypto_AES.py
Normal file
@@ -0,0 +1,22 @@
|
||||
"""PyCrypto AES implementation."""
|
||||
|
||||
from cryptomath import *
|
||||
from AES import *
|
||||
|
||||
if pycryptoLoaded:
|
||||
import Crypto.Cipher.AES
|
||||
|
||||
def new(key, mode, IV):
|
||||
return PyCrypto_AES(key, mode, IV)
|
||||
|
||||
class PyCrypto_AES(AES):
|
||||
|
||||
def __init__(self, key, mode, IV):
|
||||
AES.__init__(self, key, mode, IV, "pycrypto")
|
||||
self.context = Crypto.Cipher.AES.new(key, mode, IV)
|
||||
|
||||
def encrypt(self, plaintext):
|
||||
return self.context.encrypt(plaintext)
|
||||
|
||||
def decrypt(self, ciphertext):
|
||||
return self.context.decrypt(ciphertext)
|
22
python/gdata/tlslite/utils/PyCrypto_RC4.py
Normal file
22
python/gdata/tlslite/utils/PyCrypto_RC4.py
Normal file
@@ -0,0 +1,22 @@
|
||||
"""PyCrypto RC4 implementation."""
|
||||
|
||||
from cryptomath import *
|
||||
from RC4 import *
|
||||
|
||||
if pycryptoLoaded:
|
||||
import Crypto.Cipher.ARC4
|
||||
|
||||
def new(key):
|
||||
return PyCrypto_RC4(key)
|
||||
|
||||
class PyCrypto_RC4(RC4):
|
||||
|
||||
def __init__(self, key):
|
||||
RC4.__init__(self, key, "pycrypto")
|
||||
self.context = Crypto.Cipher.ARC4.new(key)
|
||||
|
||||
def encrypt(self, plaintext):
|
||||
return self.context.encrypt(plaintext)
|
||||
|
||||
def decrypt(self, ciphertext):
|
||||
return self.context.decrypt(ciphertext)
|
61
python/gdata/tlslite/utils/PyCrypto_RSAKey.py
Normal file
61
python/gdata/tlslite/utils/PyCrypto_RSAKey.py
Normal file
@@ -0,0 +1,61 @@
|
||||
"""PyCrypto RSA implementation."""
|
||||
|
||||
from cryptomath import *
|
||||
|
||||
from RSAKey import *
|
||||
from Python_RSAKey import Python_RSAKey
|
||||
|
||||
if pycryptoLoaded:
|
||||
|
||||
from Crypto.PublicKey import RSA
|
||||
|
||||
class PyCrypto_RSAKey(RSAKey):
|
||||
def __init__(self, n=0, e=0, d=0, p=0, q=0, dP=0, dQ=0, qInv=0):
|
||||
if not d:
|
||||
self.rsa = RSA.construct( (n, e) )
|
||||
else:
|
||||
self.rsa = RSA.construct( (n, e, d, p, q) )
|
||||
|
||||
def __getattr__(self, name):
|
||||
return getattr(self.rsa, name)
|
||||
|
||||
def hasPrivateKey(self):
|
||||
return self.rsa.has_private()
|
||||
|
||||
def hash(self):
|
||||
return Python_RSAKey(self.n, self.e).hash()
|
||||
|
||||
def _rawPrivateKeyOp(self, m):
|
||||
s = numberToString(m)
|
||||
byteLength = numBytes(self.n)
|
||||
if len(s)== byteLength:
|
||||
pass
|
||||
elif len(s) == byteLength-1:
|
||||
s = '\0' + s
|
||||
else:
|
||||
raise AssertionError()
|
||||
c = stringToNumber(self.rsa.decrypt((s,)))
|
||||
return c
|
||||
|
||||
def _rawPublicKeyOp(self, c):
|
||||
s = numberToString(c)
|
||||
byteLength = numBytes(self.n)
|
||||
if len(s)== byteLength:
|
||||
pass
|
||||
elif len(s) == byteLength-1:
|
||||
s = '\0' + s
|
||||
else:
|
||||
raise AssertionError()
|
||||
m = stringToNumber(self.rsa.encrypt(s, None)[0])
|
||||
return m
|
||||
|
||||
def writeXMLPublicKey(self, indent=''):
|
||||
return Python_RSAKey(self.n, self.e).write(indent)
|
||||
|
||||
def generate(bits):
|
||||
key = PyCrypto_RSAKey()
|
||||
def f(numBytes):
|
||||
return bytesToString(getRandomBytes(numBytes))
|
||||
key.rsa = RSA.generate(bits, f)
|
||||
return key
|
||||
generate = staticmethod(generate)
|
22
python/gdata/tlslite/utils/PyCrypto_TripleDES.py
Normal file
22
python/gdata/tlslite/utils/PyCrypto_TripleDES.py
Normal file
@@ -0,0 +1,22 @@
|
||||
"""PyCrypto 3DES implementation."""
|
||||
|
||||
from cryptomath import *
|
||||
from TripleDES import *
|
||||
|
||||
if pycryptoLoaded:
|
||||
import Crypto.Cipher.DES3
|
||||
|
||||
def new(key, mode, IV):
|
||||
return PyCrypto_TripleDES(key, mode, IV)
|
||||
|
||||
class PyCrypto_TripleDES(TripleDES):
|
||||
|
||||
def __init__(self, key, mode, IV):
|
||||
TripleDES.__init__(self, key, mode, IV, "pycrypto")
|
||||
self.context = Crypto.Cipher.DES3.new(key, mode, IV)
|
||||
|
||||
def encrypt(self, plaintext):
|
||||
return self.context.encrypt(plaintext)
|
||||
|
||||
def decrypt(self, ciphertext):
|
||||
return self.context.decrypt(ciphertext)
|
68
python/gdata/tlslite/utils/Python_AES.py
Normal file
68
python/gdata/tlslite/utils/Python_AES.py
Normal file
@@ -0,0 +1,68 @@
|
||||
"""Pure-Python AES implementation."""
|
||||
|
||||
from cryptomath import *
|
||||
|
||||
from AES import *
|
||||
from rijndael import rijndael
|
||||
|
||||
def new(key, mode, IV):
|
||||
return Python_AES(key, mode, IV)
|
||||
|
||||
class Python_AES(AES):
|
||||
def __init__(self, key, mode, IV):
|
||||
AES.__init__(self, key, mode, IV, "python")
|
||||
self.rijndael = rijndael(key, 16)
|
||||
self.IV = IV
|
||||
|
||||
def encrypt(self, plaintext):
|
||||
AES.encrypt(self, plaintext)
|
||||
|
||||
plaintextBytes = stringToBytes(plaintext)
|
||||
chainBytes = stringToBytes(self.IV)
|
||||
|
||||
#CBC Mode: For each block...
|
||||
for x in range(len(plaintextBytes)/16):
|
||||
|
||||
#XOR with the chaining block
|
||||
blockBytes = plaintextBytes[x*16 : (x*16)+16]
|
||||
for y in range(16):
|
||||
blockBytes[y] ^= chainBytes[y]
|
||||
blockString = bytesToString(blockBytes)
|
||||
|
||||
#Encrypt it
|
||||
encryptedBytes = stringToBytes(self.rijndael.encrypt(blockString))
|
||||
|
||||
#Overwrite the input with the output
|
||||
for y in range(16):
|
||||
plaintextBytes[(x*16)+y] = encryptedBytes[y]
|
||||
|
||||
#Set the next chaining block
|
||||
chainBytes = encryptedBytes
|
||||
|
||||
self.IV = bytesToString(chainBytes)
|
||||
return bytesToString(plaintextBytes)
|
||||
|
||||
def decrypt(self, ciphertext):
|
||||
AES.decrypt(self, ciphertext)
|
||||
|
||||
ciphertextBytes = stringToBytes(ciphertext)
|
||||
chainBytes = stringToBytes(self.IV)
|
||||
|
||||
#CBC Mode: For each block...
|
||||
for x in range(len(ciphertextBytes)/16):
|
||||
|
||||
#Decrypt it
|
||||
blockBytes = ciphertextBytes[x*16 : (x*16)+16]
|
||||
blockString = bytesToString(blockBytes)
|
||||
decryptedBytes = stringToBytes(self.rijndael.decrypt(blockString))
|
||||
|
||||
#XOR with the chaining block and overwrite the input with output
|
||||
for y in range(16):
|
||||
decryptedBytes[y] ^= chainBytes[y]
|
||||
ciphertextBytes[(x*16)+y] = decryptedBytes[y]
|
||||
|
||||
#Set the next chaining block
|
||||
chainBytes = blockBytes
|
||||
|
||||
self.IV = bytesToString(chainBytes)
|
||||
return bytesToString(ciphertextBytes)
|
39
python/gdata/tlslite/utils/Python_RC4.py
Normal file
39
python/gdata/tlslite/utils/Python_RC4.py
Normal file
@@ -0,0 +1,39 @@
|
||||
"""Pure-Python RC4 implementation."""
|
||||
|
||||
from RC4 import RC4
|
||||
from cryptomath import *
|
||||
|
||||
def new(key):
|
||||
return Python_RC4(key)
|
||||
|
||||
class Python_RC4(RC4):
|
||||
def __init__(self, key):
|
||||
RC4.__init__(self, key, "python")
|
||||
keyBytes = stringToBytes(key)
|
||||
S = [i for i in range(256)]
|
||||
j = 0
|
||||
for i in range(256):
|
||||
j = (j + S[i] + keyBytes[i % len(keyBytes)]) % 256
|
||||
S[i], S[j] = S[j], S[i]
|
||||
|
||||
self.S = S
|
||||
self.i = 0
|
||||
self.j = 0
|
||||
|
||||
def encrypt(self, plaintext):
|
||||
plaintextBytes = stringToBytes(plaintext)
|
||||
S = self.S
|
||||
i = self.i
|
||||
j = self.j
|
||||
for x in range(len(plaintextBytes)):
|
||||
i = (i + 1) % 256
|
||||
j = (j + S[i]) % 256
|
||||
S[i], S[j] = S[j], S[i]
|
||||
t = (S[i] + S[j]) % 256
|
||||
plaintextBytes[x] ^= S[t]
|
||||
self.i = i
|
||||
self.j = j
|
||||
return bytesToString(plaintextBytes)
|
||||
|
||||
def decrypt(self, ciphertext):
|
||||
return self.encrypt(ciphertext)
|
209
python/gdata/tlslite/utils/Python_RSAKey.py
Normal file
209
python/gdata/tlslite/utils/Python_RSAKey.py
Normal file
@@ -0,0 +1,209 @@
|
||||
"""Pure-Python RSA implementation."""
|
||||
|
||||
from cryptomath import *
|
||||
import xmltools
|
||||
from ASN1Parser import ASN1Parser
|
||||
from RSAKey import *
|
||||
|
||||
class Python_RSAKey(RSAKey):
|
||||
def __init__(self, n=0, e=0, d=0, p=0, q=0, dP=0, dQ=0, qInv=0):
|
||||
if (n and not e) or (e and not n):
|
||||
raise AssertionError()
|
||||
self.n = n
|
||||
self.e = e
|
||||
self.d = d
|
||||
self.p = p
|
||||
self.q = q
|
||||
self.dP = dP
|
||||
self.dQ = dQ
|
||||
self.qInv = qInv
|
||||
self.blinder = 0
|
||||
self.unblinder = 0
|
||||
|
||||
def hasPrivateKey(self):
|
||||
return self.d != 0
|
||||
|
||||
def hash(self):
|
||||
s = self.writeXMLPublicKey('\t\t')
|
||||
return hashAndBase64(s.strip())
|
||||
|
||||
def _rawPrivateKeyOp(self, m):
|
||||
#Create blinding values, on the first pass:
|
||||
if not self.blinder:
|
||||
self.unblinder = getRandomNumber(2, self.n)
|
||||
self.blinder = powMod(invMod(self.unblinder, self.n), self.e,
|
||||
self.n)
|
||||
|
||||
#Blind the input
|
||||
m = (m * self.blinder) % self.n
|
||||
|
||||
#Perform the RSA operation
|
||||
c = self._rawPrivateKeyOpHelper(m)
|
||||
|
||||
#Unblind the output
|
||||
c = (c * self.unblinder) % self.n
|
||||
|
||||
#Update blinding values
|
||||
self.blinder = (self.blinder * self.blinder) % self.n
|
||||
self.unblinder = (self.unblinder * self.unblinder) % self.n
|
||||
|
||||
#Return the output
|
||||
return c
|
||||
|
||||
|
||||
def _rawPrivateKeyOpHelper(self, m):
|
||||
#Non-CRT version
|
||||
#c = powMod(m, self.d, self.n)
|
||||
|
||||
#CRT version (~3x faster)
|
||||
s1 = powMod(m, self.dP, self.p)
|
||||
s2 = powMod(m, self.dQ, self.q)
|
||||
h = ((s1 - s2) * self.qInv) % self.p
|
||||
c = s2 + self.q * h
|
||||
return c
|
||||
|
||||
def _rawPublicKeyOp(self, c):
|
||||
m = powMod(c, self.e, self.n)
|
||||
return m
|
||||
|
||||
def acceptsPassword(self): return False
|
||||
|
||||
def write(self, indent=''):
|
||||
if self.d:
|
||||
s = indent+'<privateKey xmlns="http://trevp.net/rsa">\n'
|
||||
else:
|
||||
s = indent+'<publicKey xmlns="http://trevp.net/rsa">\n'
|
||||
s += indent+'\t<n>%s</n>\n' % numberToBase64(self.n)
|
||||
s += indent+'\t<e>%s</e>\n' % numberToBase64(self.e)
|
||||
if self.d:
|
||||
s += indent+'\t<d>%s</d>\n' % numberToBase64(self.d)
|
||||
s += indent+'\t<p>%s</p>\n' % numberToBase64(self.p)
|
||||
s += indent+'\t<q>%s</q>\n' % numberToBase64(self.q)
|
||||
s += indent+'\t<dP>%s</dP>\n' % numberToBase64(self.dP)
|
||||
s += indent+'\t<dQ>%s</dQ>\n' % numberToBase64(self.dQ)
|
||||
s += indent+'\t<qInv>%s</qInv>\n' % numberToBase64(self.qInv)
|
||||
s += indent+'</privateKey>'
|
||||
else:
|
||||
s += indent+'</publicKey>'
|
||||
#Only add \n if part of a larger structure
|
||||
if indent != '':
|
||||
s += '\n'
|
||||
return s
|
||||
|
||||
def writeXMLPublicKey(self, indent=''):
|
||||
return Python_RSAKey(self.n, self.e).write(indent)
|
||||
|
||||
def generate(bits):
|
||||
key = Python_RSAKey()
|
||||
p = getRandomPrime(bits/2, False)
|
||||
q = getRandomPrime(bits/2, False)
|
||||
t = lcm(p-1, q-1)
|
||||
key.n = p * q
|
||||
key.e = 3L #Needed to be long, for Java
|
||||
key.d = invMod(key.e, t)
|
||||
key.p = p
|
||||
key.q = q
|
||||
key.dP = key.d % (p-1)
|
||||
key.dQ = key.d % (q-1)
|
||||
key.qInv = invMod(q, p)
|
||||
return key
|
||||
generate = staticmethod(generate)
|
||||
|
||||
def parsePEM(s, passwordCallback=None):
|
||||
"""Parse a string containing a <privateKey> or <publicKey>, or
|
||||
PEM-encoded key."""
|
||||
|
||||
start = s.find("-----BEGIN PRIVATE KEY-----")
|
||||
if start != -1:
|
||||
end = s.find("-----END PRIVATE KEY-----")
|
||||
if end == -1:
|
||||
raise SyntaxError("Missing PEM Postfix")
|
||||
s = s[start+len("-----BEGIN PRIVATE KEY -----") : end]
|
||||
bytes = base64ToBytes(s)
|
||||
return Python_RSAKey._parsePKCS8(bytes)
|
||||
else:
|
||||
start = s.find("-----BEGIN RSA PRIVATE KEY-----")
|
||||
if start != -1:
|
||||
end = s.find("-----END RSA PRIVATE KEY-----")
|
||||
if end == -1:
|
||||
raise SyntaxError("Missing PEM Postfix")
|
||||
s = s[start+len("-----BEGIN RSA PRIVATE KEY -----") : end]
|
||||
bytes = base64ToBytes(s)
|
||||
return Python_RSAKey._parseSSLeay(bytes)
|
||||
raise SyntaxError("Missing PEM Prefix")
|
||||
parsePEM = staticmethod(parsePEM)
|
||||
|
||||
def parseXML(s):
|
||||
element = xmltools.parseAndStripWhitespace(s)
|
||||
return Python_RSAKey._parseXML(element)
|
||||
parseXML = staticmethod(parseXML)
|
||||
|
||||
def _parsePKCS8(bytes):
|
||||
p = ASN1Parser(bytes)
|
||||
|
||||
version = p.getChild(0).value[0]
|
||||
if version != 0:
|
||||
raise SyntaxError("Unrecognized PKCS8 version")
|
||||
|
||||
rsaOID = p.getChild(1).value
|
||||
if list(rsaOID) != [6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0]:
|
||||
raise SyntaxError("Unrecognized AlgorithmIdentifier")
|
||||
|
||||
#Get the privateKey
|
||||
privateKeyP = p.getChild(2)
|
||||
|
||||
#Adjust for OCTET STRING encapsulation
|
||||
privateKeyP = ASN1Parser(privateKeyP.value)
|
||||
|
||||
return Python_RSAKey._parseASN1PrivateKey(privateKeyP)
|
||||
_parsePKCS8 = staticmethod(_parsePKCS8)
|
||||
|
||||
def _parseSSLeay(bytes):
|
||||
privateKeyP = ASN1Parser(bytes)
|
||||
return Python_RSAKey._parseASN1PrivateKey(privateKeyP)
|
||||
_parseSSLeay = staticmethod(_parseSSLeay)
|
||||
|
||||
def _parseASN1PrivateKey(privateKeyP):
|
||||
version = privateKeyP.getChild(0).value[0]
|
||||
if version != 0:
|
||||
raise SyntaxError("Unrecognized RSAPrivateKey version")
|
||||
n = bytesToNumber(privateKeyP.getChild(1).value)
|
||||
e = bytesToNumber(privateKeyP.getChild(2).value)
|
||||
d = bytesToNumber(privateKeyP.getChild(3).value)
|
||||
p = bytesToNumber(privateKeyP.getChild(4).value)
|
||||
q = bytesToNumber(privateKeyP.getChild(5).value)
|
||||
dP = bytesToNumber(privateKeyP.getChild(6).value)
|
||||
dQ = bytesToNumber(privateKeyP.getChild(7).value)
|
||||
qInv = bytesToNumber(privateKeyP.getChild(8).value)
|
||||
return Python_RSAKey(n, e, d, p, q, dP, dQ, qInv)
|
||||
_parseASN1PrivateKey = staticmethod(_parseASN1PrivateKey)
|
||||
|
||||
def _parseXML(element):
|
||||
try:
|
||||
xmltools.checkName(element, "privateKey")
|
||||
except SyntaxError:
|
||||
xmltools.checkName(element, "publicKey")
|
||||
|
||||
#Parse attributes
|
||||
xmltools.getReqAttribute(element, "xmlns", "http://trevp.net/rsa\Z")
|
||||
xmltools.checkNoMoreAttributes(element)
|
||||
|
||||
#Parse public values (<n> and <e>)
|
||||
n = base64ToNumber(xmltools.getText(xmltools.getChild(element, 0, "n"), xmltools.base64RegEx))
|
||||
e = base64ToNumber(xmltools.getText(xmltools.getChild(element, 1, "e"), xmltools.base64RegEx))
|
||||
d = 0
|
||||
p = 0
|
||||
q = 0
|
||||
dP = 0
|
||||
dQ = 0
|
||||
qInv = 0
|
||||
#Parse private values, if present
|
||||
if element.childNodes.length>=3:
|
||||
d = base64ToNumber(xmltools.getText(xmltools.getChild(element, 2, "d"), xmltools.base64RegEx))
|
||||
p = base64ToNumber(xmltools.getText(xmltools.getChild(element, 3, "p"), xmltools.base64RegEx))
|
||||
q = base64ToNumber(xmltools.getText(xmltools.getChild(element, 4, "q"), xmltools.base64RegEx))
|
||||
dP = base64ToNumber(xmltools.getText(xmltools.getChild(element, 5, "dP"), xmltools.base64RegEx))
|
||||
dQ = base64ToNumber(xmltools.getText(xmltools.getChild(element, 6, "dQ"), xmltools.base64RegEx))
|
||||
qInv = base64ToNumber(xmltools.getText(xmltools.getLastChild(element, 7, "qInv"), xmltools.base64RegEx))
|
||||
return Python_RSAKey(n, e, d, p, q, dP, dQ, qInv)
|
||||
_parseXML = staticmethod(_parseXML)
|
17
python/gdata/tlslite/utils/RC4.py
Normal file
17
python/gdata/tlslite/utils/RC4.py
Normal file
@@ -0,0 +1,17 @@
|
||||
"""Abstract class for RC4."""
|
||||
|
||||
from compat import * #For False
|
||||
|
||||
class RC4:
|
||||
def __init__(self, keyBytes, implementation):
|
||||
if len(keyBytes) < 16 or len(keyBytes) > 256:
|
||||
raise ValueError()
|
||||
self.isBlockCipher = False
|
||||
self.name = "rc4"
|
||||
self.implementation = implementation
|
||||
|
||||
def encrypt(self, plaintext):
|
||||
raise NotImplementedError()
|
||||
|
||||
def decrypt(self, ciphertext):
|
||||
raise NotImplementedError()
|
264
python/gdata/tlslite/utils/RSAKey.py
Normal file
264
python/gdata/tlslite/utils/RSAKey.py
Normal file
@@ -0,0 +1,264 @@
|
||||
"""Abstract class for RSA."""
|
||||
|
||||
from cryptomath import *
|
||||
|
||||
|
||||
class RSAKey:
|
||||
"""This is an abstract base class for RSA keys.
|
||||
|
||||
Particular implementations of RSA keys, such as
|
||||
L{OpenSSL_RSAKey.OpenSSL_RSAKey},
|
||||
L{Python_RSAKey.Python_RSAKey}, and
|
||||
L{PyCrypto_RSAKey.PyCrypto_RSAKey},
|
||||
inherit from this.
|
||||
|
||||
To create or parse an RSA key, don't use one of these classes
|
||||
directly. Instead, use the factory functions in
|
||||
L{tlslite.utils.keyfactory}.
|
||||
"""
|
||||
|
||||
def __init__(self, n=0, e=0):
|
||||
"""Create a new RSA key.
|
||||
|
||||
If n and e are passed in, the new key will be initialized.
|
||||
|
||||
@type n: int
|
||||
@param n: RSA modulus.
|
||||
|
||||
@type e: int
|
||||
@param e: RSA public exponent.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def __len__(self):
|
||||
"""Return the length of this key in bits.
|
||||
|
||||
@rtype: int
|
||||
"""
|
||||
return numBits(self.n)
|
||||
|
||||
def hasPrivateKey(self):
|
||||
"""Return whether or not this key has a private component.
|
||||
|
||||
@rtype: bool
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def hash(self):
|
||||
"""Return the cryptoID <keyHash> value corresponding to this
|
||||
key.
|
||||
|
||||
@rtype: str
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def getSigningAlgorithm(self):
|
||||
"""Return the cryptoID sigAlgo value corresponding to this key.
|
||||
|
||||
@rtype: str
|
||||
"""
|
||||
return "pkcs1-sha1"
|
||||
|
||||
def hashAndSign(self, bytes):
|
||||
"""Hash and sign the passed-in bytes.
|
||||
|
||||
This requires the key to have a private component. It performs
|
||||
a PKCS1-SHA1 signature on the passed-in data.
|
||||
|
||||
@type bytes: str or L{array.array} of unsigned bytes
|
||||
@param bytes: The value which will be hashed and signed.
|
||||
|
||||
@rtype: L{array.array} of unsigned bytes.
|
||||
@return: A PKCS1-SHA1 signature on the passed-in data.
|
||||
"""
|
||||
if not isinstance(bytes, type("")):
|
||||
bytes = bytesToString(bytes)
|
||||
hashBytes = stringToBytes(sha1(bytes).digest())
|
||||
prefixedHashBytes = self._addPKCS1SHA1Prefix(hashBytes)
|
||||
sigBytes = self.sign(prefixedHashBytes)
|
||||
return sigBytes
|
||||
|
||||
def hashAndVerify(self, sigBytes, bytes):
|
||||
"""Hash and verify the passed-in bytes with the signature.
|
||||
|
||||
This verifies a PKCS1-SHA1 signature on the passed-in data.
|
||||
|
||||
@type sigBytes: L{array.array} of unsigned bytes
|
||||
@param sigBytes: A PKCS1-SHA1 signature.
|
||||
|
||||
@type bytes: str or L{array.array} of unsigned bytes
|
||||
@param bytes: The value which will be hashed and verified.
|
||||
|
||||
@rtype: bool
|
||||
@return: Whether the signature matches the passed-in data.
|
||||
"""
|
||||
if not isinstance(bytes, type("")):
|
||||
bytes = bytesToString(bytes)
|
||||
hashBytes = stringToBytes(sha1(bytes).digest())
|
||||
prefixedHashBytes = self._addPKCS1SHA1Prefix(hashBytes)
|
||||
return self.verify(sigBytes, prefixedHashBytes)
|
||||
|
||||
def sign(self, bytes):
|
||||
"""Sign the passed-in bytes.
|
||||
|
||||
This requires the key to have a private component. It performs
|
||||
a PKCS1 signature on the passed-in data.
|
||||
|
||||
@type bytes: L{array.array} of unsigned bytes
|
||||
@param bytes: The value which will be signed.
|
||||
|
||||
@rtype: L{array.array} of unsigned bytes.
|
||||
@return: A PKCS1 signature on the passed-in data.
|
||||
"""
|
||||
if not self.hasPrivateKey():
|
||||
raise AssertionError()
|
||||
paddedBytes = self._addPKCS1Padding(bytes, 1)
|
||||
m = bytesToNumber(paddedBytes)
|
||||
if m >= self.n:
|
||||
raise ValueError()
|
||||
c = self._rawPrivateKeyOp(m)
|
||||
sigBytes = numberToBytes(c)
|
||||
return sigBytes
|
||||
|
||||
def verify(self, sigBytes, bytes):
|
||||
"""Verify the passed-in bytes with the signature.
|
||||
|
||||
This verifies a PKCS1 signature on the passed-in data.
|
||||
|
||||
@type sigBytes: L{array.array} of unsigned bytes
|
||||
@param sigBytes: A PKCS1 signature.
|
||||
|
||||
@type bytes: L{array.array} of unsigned bytes
|
||||
@param bytes: The value which will be verified.
|
||||
|
||||
@rtype: bool
|
||||
@return: Whether the signature matches the passed-in data.
|
||||
"""
|
||||
paddedBytes = self._addPKCS1Padding(bytes, 1)
|
||||
c = bytesToNumber(sigBytes)
|
||||
if c >= self.n:
|
||||
return False
|
||||
m = self._rawPublicKeyOp(c)
|
||||
checkBytes = numberToBytes(m)
|
||||
return checkBytes == paddedBytes
|
||||
|
||||
def encrypt(self, bytes):
|
||||
"""Encrypt the passed-in bytes.
|
||||
|
||||
This performs PKCS1 encryption of the passed-in data.
|
||||
|
||||
@type bytes: L{array.array} of unsigned bytes
|
||||
@param bytes: The value which will be encrypted.
|
||||
|
||||
@rtype: L{array.array} of unsigned bytes.
|
||||
@return: A PKCS1 encryption of the passed-in data.
|
||||
"""
|
||||
paddedBytes = self._addPKCS1Padding(bytes, 2)
|
||||
m = bytesToNumber(paddedBytes)
|
||||
if m >= self.n:
|
||||
raise ValueError()
|
||||
c = self._rawPublicKeyOp(m)
|
||||
encBytes = numberToBytes(c)
|
||||
return encBytes
|
||||
|
||||
def decrypt(self, encBytes):
|
||||
"""Decrypt the passed-in bytes.
|
||||
|
||||
This requires the key to have a private component. It performs
|
||||
PKCS1 decryption of the passed-in data.
|
||||
|
||||
@type encBytes: L{array.array} of unsigned bytes
|
||||
@param encBytes: The value which will be decrypted.
|
||||
|
||||
@rtype: L{array.array} of unsigned bytes or None.
|
||||
@return: A PKCS1 decryption of the passed-in data or None if
|
||||
the data is not properly formatted.
|
||||
"""
|
||||
if not self.hasPrivateKey():
|
||||
raise AssertionError()
|
||||
c = bytesToNumber(encBytes)
|
||||
if c >= self.n:
|
||||
return None
|
||||
m = self._rawPrivateKeyOp(c)
|
||||
decBytes = numberToBytes(m)
|
||||
if (len(decBytes) != numBytes(self.n)-1): #Check first byte
|
||||
return None
|
||||
if decBytes[0] != 2: #Check second byte
|
||||
return None
|
||||
for x in range(len(decBytes)-1): #Scan through for zero separator
|
||||
if decBytes[x]== 0:
|
||||
break
|
||||
else:
|
||||
return None
|
||||
return decBytes[x+1:] #Return everything after the separator
|
||||
|
||||
def _rawPrivateKeyOp(self, m):
|
||||
raise NotImplementedError()
|
||||
|
||||
def _rawPublicKeyOp(self, c):
|
||||
raise NotImplementedError()
|
||||
|
||||
def acceptsPassword(self):
|
||||
"""Return True if the write() method accepts a password for use
|
||||
in encrypting the private key.
|
||||
|
||||
@rtype: bool
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def write(self, password=None):
|
||||
"""Return a string containing the key.
|
||||
|
||||
@rtype: str
|
||||
@return: A string describing the key, in whichever format (PEM
|
||||
or XML) is native to the implementation.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def writeXMLPublicKey(self, indent=''):
|
||||
"""Return a string containing the key.
|
||||
|
||||
@rtype: str
|
||||
@return: A string describing the public key, in XML format.
|
||||
"""
|
||||
return Python_RSAKey(self.n, self.e).write(indent)
|
||||
|
||||
def generate(bits):
|
||||
"""Generate a new key with the specified bit length.
|
||||
|
||||
@rtype: L{tlslite.utils.RSAKey.RSAKey}
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
generate = staticmethod(generate)
|
||||
|
||||
|
||||
# **************************************************************************
|
||||
# Helper Functions for RSA Keys
|
||||
# **************************************************************************
|
||||
|
||||
def _addPKCS1SHA1Prefix(self, bytes):
|
||||
prefixBytes = createByteArraySequence(\
|
||||
[48,33,48,9,6,5,43,14,3,2,26,5,0,4,20])
|
||||
prefixedBytes = prefixBytes + bytes
|
||||
return prefixedBytes
|
||||
|
||||
def _addPKCS1Padding(self, bytes, blockType):
|
||||
padLength = (numBytes(self.n) - (len(bytes)+3))
|
||||
if blockType == 1: #Signature padding
|
||||
pad = [0xFF] * padLength
|
||||
elif blockType == 2: #Encryption padding
|
||||
pad = createByteArraySequence([])
|
||||
while len(pad) < padLength:
|
||||
padBytes = getRandomBytes(padLength * 2)
|
||||
pad = [b for b in padBytes if b != 0]
|
||||
pad = pad[:padLength]
|
||||
else:
|
||||
raise AssertionError()
|
||||
|
||||
#NOTE: To be proper, we should add [0,blockType]. However,
|
||||
#the zero is lost when the returned padding is converted
|
||||
#to a number, so we don't even bother with it. Also,
|
||||
#adding it would cause a misalignment in verify()
|
||||
padding = createByteArraySequence([blockType] + pad + [0])
|
||||
paddedBytes = padding + bytes
|
||||
return paddedBytes
|
26
python/gdata/tlslite/utils/TripleDES.py
Normal file
26
python/gdata/tlslite/utils/TripleDES.py
Normal file
@@ -0,0 +1,26 @@
|
||||
"""Abstract class for 3DES."""
|
||||
|
||||
from compat import * #For True
|
||||
|
||||
class TripleDES:
|
||||
def __init__(self, key, mode, IV, implementation):
|
||||
if len(key) != 24:
|
||||
raise ValueError()
|
||||
if mode != 2:
|
||||
raise ValueError()
|
||||
if len(IV) != 8:
|
||||
raise ValueError()
|
||||
self.isBlockCipher = True
|
||||
self.block_size = 8
|
||||
self.implementation = implementation
|
||||
self.name = "3des"
|
||||
|
||||
#CBC-Mode encryption, returns ciphertext
|
||||
#WARNING: *MAY* modify the input as well
|
||||
def encrypt(self, plaintext):
|
||||
assert(len(plaintext) % 8 == 0)
|
||||
|
||||
#CBC-Mode decryption, returns plaintext
|
||||
#WARNING: *MAY* modify the input as well
|
||||
def decrypt(self, ciphertext):
|
||||
assert(len(ciphertext) % 8 == 0)
|
31
python/gdata/tlslite/utils/__init__.py
Normal file
31
python/gdata/tlslite/utils/__init__.py
Normal file
@@ -0,0 +1,31 @@
|
||||
"""Toolkit for crypto and other stuff."""
|
||||
|
||||
__all__ = ["AES",
|
||||
"ASN1Parser",
|
||||
"cipherfactory",
|
||||
"codec",
|
||||
"Cryptlib_AES",
|
||||
"Cryptlib_RC4",
|
||||
"Cryptlib_TripleDES",
|
||||
"cryptomath: cryptomath module",
|
||||
"dateFuncs",
|
||||
"hmac",
|
||||
"JCE_RSAKey",
|
||||
"compat",
|
||||
"keyfactory",
|
||||
"OpenSSL_AES",
|
||||
"OpenSSL_RC4",
|
||||
"OpenSSL_RSAKey",
|
||||
"OpenSSL_TripleDES",
|
||||
"PyCrypto_AES",
|
||||
"PyCrypto_RC4",
|
||||
"PyCrypto_RSAKey",
|
||||
"PyCrypto_TripleDES",
|
||||
"Python_AES",
|
||||
"Python_RC4",
|
||||
"Python_RSAKey",
|
||||
"RC4",
|
||||
"rijndael",
|
||||
"RSAKey",
|
||||
"TripleDES",
|
||||
"xmltools"]
|
111
python/gdata/tlslite/utils/cipherfactory.py
Normal file
111
python/gdata/tlslite/utils/cipherfactory.py
Normal file
@@ -0,0 +1,111 @@
|
||||
"""Factory functions for symmetric cryptography."""
|
||||
|
||||
import os
|
||||
|
||||
import Python_AES
|
||||
import Python_RC4
|
||||
|
||||
import cryptomath
|
||||
|
||||
tripleDESPresent = False
|
||||
|
||||
if cryptomath.m2cryptoLoaded:
|
||||
import OpenSSL_AES
|
||||
import OpenSSL_RC4
|
||||
import OpenSSL_TripleDES
|
||||
tripleDESPresent = True
|
||||
|
||||
if cryptomath.cryptlibpyLoaded:
|
||||
import Cryptlib_AES
|
||||
import Cryptlib_RC4
|
||||
import Cryptlib_TripleDES
|
||||
tripleDESPresent = True
|
||||
|
||||
if cryptomath.pycryptoLoaded:
|
||||
import PyCrypto_AES
|
||||
import PyCrypto_RC4
|
||||
import PyCrypto_TripleDES
|
||||
tripleDESPresent = True
|
||||
|
||||
# **************************************************************************
|
||||
# Factory Functions for AES
|
||||
# **************************************************************************
|
||||
|
||||
def createAES(key, IV, implList=None):
|
||||
"""Create a new AES object.
|
||||
|
||||
@type key: str
|
||||
@param key: A 16, 24, or 32 byte string.
|
||||
|
||||
@type IV: str
|
||||
@param IV: A 16 byte string
|
||||
|
||||
@rtype: L{tlslite.utils.AES}
|
||||
@return: An AES object.
|
||||
"""
|
||||
if implList == None:
|
||||
implList = ["cryptlib", "openssl", "pycrypto", "python"]
|
||||
|
||||
for impl in implList:
|
||||
if impl == "cryptlib" and cryptomath.cryptlibpyLoaded:
|
||||
return Cryptlib_AES.new(key, 2, IV)
|
||||
elif impl == "openssl" and cryptomath.m2cryptoLoaded:
|
||||
return OpenSSL_AES.new(key, 2, IV)
|
||||
elif impl == "pycrypto" and cryptomath.pycryptoLoaded:
|
||||
return PyCrypto_AES.new(key, 2, IV)
|
||||
elif impl == "python":
|
||||
return Python_AES.new(key, 2, IV)
|
||||
raise NotImplementedError()
|
||||
|
||||
def createRC4(key, IV, implList=None):
|
||||
"""Create a new RC4 object.
|
||||
|
||||
@type key: str
|
||||
@param key: A 16 to 32 byte string.
|
||||
|
||||
@type IV: object
|
||||
@param IV: Ignored, whatever it is.
|
||||
|
||||
@rtype: L{tlslite.utils.RC4}
|
||||
@return: An RC4 object.
|
||||
"""
|
||||
if implList == None:
|
||||
implList = ["cryptlib", "openssl", "pycrypto", "python"]
|
||||
|
||||
if len(IV) != 0:
|
||||
raise AssertionError()
|
||||
for impl in implList:
|
||||
if impl == "cryptlib" and cryptomath.cryptlibpyLoaded:
|
||||
return Cryptlib_RC4.new(key)
|
||||
elif impl == "openssl" and cryptomath.m2cryptoLoaded:
|
||||
return OpenSSL_RC4.new(key)
|
||||
elif impl == "pycrypto" and cryptomath.pycryptoLoaded:
|
||||
return PyCrypto_RC4.new(key)
|
||||
elif impl == "python":
|
||||
return Python_RC4.new(key)
|
||||
raise NotImplementedError()
|
||||
|
||||
#Create a new TripleDES instance
|
||||
def createTripleDES(key, IV, implList=None):
|
||||
"""Create a new 3DES object.
|
||||
|
||||
@type key: str
|
||||
@param key: A 24 byte string.
|
||||
|
||||
@type IV: str
|
||||
@param IV: An 8 byte string
|
||||
|
||||
@rtype: L{tlslite.utils.TripleDES}
|
||||
@return: A 3DES object.
|
||||
"""
|
||||
if implList == None:
|
||||
implList = ["cryptlib", "openssl", "pycrypto"]
|
||||
|
||||
for impl in implList:
|
||||
if impl == "cryptlib" and cryptomath.cryptlibpyLoaded:
|
||||
return Cryptlib_TripleDES.new(key, 2, IV)
|
||||
elif impl == "openssl" and cryptomath.m2cryptoLoaded:
|
||||
return OpenSSL_TripleDES.new(key, 2, IV)
|
||||
elif impl == "pycrypto" and cryptomath.pycryptoLoaded:
|
||||
return PyCrypto_TripleDES.new(key, 2, IV)
|
||||
raise NotImplementedError()
|
94
python/gdata/tlslite/utils/codec.py
Normal file
94
python/gdata/tlslite/utils/codec.py
Normal file
@@ -0,0 +1,94 @@
|
||||
"""Classes for reading/writing binary data (such as TLS records)."""
|
||||
|
||||
from compat import *
|
||||
|
||||
class Writer:
|
||||
def __init__(self, length=0):
|
||||
#If length is zero, then this is just a "trial run" to determine length
|
||||
self.index = 0
|
||||
self.bytes = createByteArrayZeros(length)
|
||||
|
||||
def add(self, x, length):
|
||||
if self.bytes:
|
||||
newIndex = self.index+length-1
|
||||
while newIndex >= self.index:
|
||||
self.bytes[newIndex] = x & 0xFF
|
||||
x >>= 8
|
||||
newIndex -= 1
|
||||
self.index += length
|
||||
|
||||
def addFixSeq(self, seq, length):
|
||||
if self.bytes:
|
||||
for e in seq:
|
||||
self.add(e, length)
|
||||
else:
|
||||
self.index += len(seq)*length
|
||||
|
||||
def addVarSeq(self, seq, length, lengthLength):
|
||||
if self.bytes:
|
||||
self.add(len(seq)*length, lengthLength)
|
||||
for e in seq:
|
||||
self.add(e, length)
|
||||
else:
|
||||
self.index += lengthLength + (len(seq)*length)
|
||||
|
||||
|
||||
class Parser:
|
||||
def __init__(self, bytes):
|
||||
self.bytes = bytes
|
||||
self.index = 0
|
||||
|
||||
def get(self, length):
|
||||
if self.index + length > len(self.bytes):
|
||||
raise SyntaxError()
|
||||
x = 0
|
||||
for count in range(length):
|
||||
x <<= 8
|
||||
x |= self.bytes[self.index]
|
||||
self.index += 1
|
||||
return x
|
||||
|
||||
def getFixBytes(self, lengthBytes):
|
||||
bytes = self.bytes[self.index : self.index+lengthBytes]
|
||||
self.index += lengthBytes
|
||||
return bytes
|
||||
|
||||
def getVarBytes(self, lengthLength):
|
||||
lengthBytes = self.get(lengthLength)
|
||||
return self.getFixBytes(lengthBytes)
|
||||
|
||||
def getFixList(self, length, lengthList):
|
||||
l = [0] * lengthList
|
||||
for x in range(lengthList):
|
||||
l[x] = self.get(length)
|
||||
return l
|
||||
|
||||
def getVarList(self, length, lengthLength):
|
||||
lengthList = self.get(lengthLength)
|
||||
if lengthList % length != 0:
|
||||
raise SyntaxError()
|
||||
lengthList = int(lengthList/length)
|
||||
l = [0] * lengthList
|
||||
for x in range(lengthList):
|
||||
l[x] = self.get(length)
|
||||
return l
|
||||
|
||||
def startLengthCheck(self, lengthLength):
|
||||
self.lengthCheck = self.get(lengthLength)
|
||||
self.indexCheck = self.index
|
||||
|
||||
def setLengthCheck(self, length):
|
||||
self.lengthCheck = length
|
||||
self.indexCheck = self.index
|
||||
|
||||
def stopLengthCheck(self):
|
||||
if (self.index - self.indexCheck) != self.lengthCheck:
|
||||
raise SyntaxError()
|
||||
|
||||
def atLengthCheck(self):
|
||||
if (self.index - self.indexCheck) < self.lengthCheck:
|
||||
return False
|
||||
elif (self.index - self.indexCheck) == self.lengthCheck:
|
||||
return True
|
||||
else:
|
||||
raise SyntaxError()
|
140
python/gdata/tlslite/utils/compat.py
Normal file
140
python/gdata/tlslite/utils/compat.py
Normal file
@@ -0,0 +1,140 @@
|
||||
"""Miscellaneous functions to mask Python version differences."""
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
if sys.version_info < (2,2):
|
||||
raise AssertionError("Python 2.2 or later required")
|
||||
|
||||
if sys.version_info < (2,3):
|
||||
|
||||
def enumerate(collection):
|
||||
return zip(range(len(collection)), collection)
|
||||
|
||||
class Set:
|
||||
def __init__(self, seq=None):
|
||||
self.values = {}
|
||||
if seq:
|
||||
for e in seq:
|
||||
self.values[e] = None
|
||||
|
||||
def add(self, e):
|
||||
self.values[e] = None
|
||||
|
||||
def discard(self, e):
|
||||
if e in self.values.keys():
|
||||
del(self.values[e])
|
||||
|
||||
def union(self, s):
|
||||
ret = Set()
|
||||
for e in self.values.keys():
|
||||
ret.values[e] = None
|
||||
for e in s.values.keys():
|
||||
ret.values[e] = None
|
||||
return ret
|
||||
|
||||
def issubset(self, other):
|
||||
for e in self.values.keys():
|
||||
if e not in other.values.keys():
|
||||
return False
|
||||
return True
|
||||
|
||||
def __nonzero__( self):
|
||||
return len(self.values.keys())
|
||||
|
||||
def __contains__(self, e):
|
||||
return e in self.values.keys()
|
||||
|
||||
def __iter__(self):
|
||||
return iter(set.values.keys())
|
||||
|
||||
|
||||
if os.name != "java":
|
||||
|
||||
import array
|
||||
def createByteArraySequence(seq):
|
||||
return array.array('B', seq)
|
||||
def createByteArrayZeros(howMany):
|
||||
return array.array('B', [0] * howMany)
|
||||
def concatArrays(a1, a2):
|
||||
return a1+a2
|
||||
|
||||
def bytesToString(bytes):
|
||||
return bytes.tostring()
|
||||
def stringToBytes(s):
|
||||
bytes = createByteArrayZeros(0)
|
||||
bytes.fromstring(s)
|
||||
return bytes
|
||||
|
||||
import math
|
||||
def numBits(n):
|
||||
if n==0:
|
||||
return 0
|
||||
s = "%x" % n
|
||||
return ((len(s)-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,
|
||||
}[s[0]]
|
||||
return int(math.floor(math.log(n, 2))+1)
|
||||
|
||||
BaseException = Exception
|
||||
import sys
|
||||
import traceback
|
||||
def formatExceptionTrace(e):
|
||||
newStr = "".join(traceback.format_exception(sys.exc_type, sys.exc_value, sys.exc_traceback))
|
||||
return newStr
|
||||
|
||||
else:
|
||||
#Jython 2.1 is missing lots of python 2.3 stuff,
|
||||
#which we have to emulate here:
|
||||
#NOTE: JYTHON SUPPORT NO LONGER WORKS, DUE TO USE OF GENERATORS.
|
||||
#THIS CODE IS LEFT IN SO THAT ONE JYTHON UPDATES TO 2.2, IT HAS A
|
||||
#CHANCE OF WORKING AGAIN.
|
||||
|
||||
import java
|
||||
import jarray
|
||||
|
||||
def createByteArraySequence(seq):
|
||||
if isinstance(seq, type("")): #If it's a string, convert
|
||||
seq = [ord(c) for c in seq]
|
||||
return jarray.array(seq, 'h') #use short instead of bytes, cause bytes are signed
|
||||
def createByteArrayZeros(howMany):
|
||||
return jarray.zeros(howMany, 'h') #use short instead of bytes, cause bytes are signed
|
||||
def concatArrays(a1, a2):
|
||||
l = list(a1)+list(a2)
|
||||
return createByteArraySequence(l)
|
||||
|
||||
#WAY TOO SLOW - MUST BE REPLACED------------
|
||||
def bytesToString(bytes):
|
||||
return "".join([chr(b) for b in bytes])
|
||||
|
||||
def stringToBytes(s):
|
||||
bytes = createByteArrayZeros(len(s))
|
||||
for count, c in enumerate(s):
|
||||
bytes[count] = ord(c)
|
||||
return bytes
|
||||
#WAY TOO SLOW - MUST BE REPLACED------------
|
||||
|
||||
def numBits(n):
|
||||
if n==0:
|
||||
return 0
|
||||
n= 1L * n; #convert to long, if it isn't already
|
||||
return n.__tojava__(java.math.BigInteger).bitLength()
|
||||
|
||||
#Adjust the string to an array of bytes
|
||||
def stringToJavaByteArray(s):
|
||||
bytes = jarray.zeros(len(s), 'b')
|
||||
for count, c in enumerate(s):
|
||||
x = ord(c)
|
||||
if x >= 128: x -= 256
|
||||
bytes[count] = x
|
||||
return bytes
|
||||
|
||||
BaseException = java.lang.Exception
|
||||
import sys
|
||||
import traceback
|
||||
def formatExceptionTrace(e):
|
||||
newStr = "".join(traceback.format_exception(sys.exc_type, sys.exc_value, sys.exc_traceback))
|
||||
return newStr
|
404
python/gdata/tlslite/utils/cryptomath.py
Normal file
404
python/gdata/tlslite/utils/cryptomath.py
Normal file
@@ -0,0 +1,404 @@
|
||||
"""cryptomath module
|
||||
|
||||
This module has basic math/crypto code."""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import math
|
||||
import base64
|
||||
import binascii
|
||||
if sys.version_info[:2] <= (2, 4):
|
||||
from sha import sha as sha1
|
||||
else:
|
||||
from hashlib import sha1
|
||||
|
||||
from compat import *
|
||||
|
||||
|
||||
# **************************************************************************
|
||||
# Load Optional Modules
|
||||
# **************************************************************************
|
||||
|
||||
# Try to load M2Crypto/OpenSSL
|
||||
try:
|
||||
from M2Crypto import m2
|
||||
m2cryptoLoaded = True
|
||||
|
||||
except ImportError:
|
||||
m2cryptoLoaded = False
|
||||
|
||||
|
||||
# Try to load cryptlib
|
||||
try:
|
||||
import cryptlib_py
|
||||
try:
|
||||
cryptlib_py.cryptInit()
|
||||
except cryptlib_py.CryptException, e:
|
||||
#If tlslite and cryptoIDlib are both present,
|
||||
#they might each try to re-initialize this,
|
||||
#so we're tolerant of that.
|
||||
if e[0] != cryptlib_py.CRYPT_ERROR_INITED:
|
||||
raise
|
||||
cryptlibpyLoaded = True
|
||||
|
||||
except ImportError:
|
||||
cryptlibpyLoaded = False
|
||||
|
||||
#Try to load GMPY
|
||||
try:
|
||||
import gmpy
|
||||
gmpyLoaded = True
|
||||
except ImportError:
|
||||
gmpyLoaded = False
|
||||
|
||||
#Try to load pycrypto
|
||||
try:
|
||||
import Crypto.Cipher.AES
|
||||
pycryptoLoaded = True
|
||||
except ImportError:
|
||||
pycryptoLoaded = False
|
||||
|
||||
|
||||
# **************************************************************************
|
||||
# PRNG Functions
|
||||
# **************************************************************************
|
||||
|
||||
# Get os.urandom PRNG
|
||||
try:
|
||||
os.urandom(1)
|
||||
def getRandomBytes(howMany):
|
||||
return stringToBytes(os.urandom(howMany))
|
||||
prngName = "os.urandom"
|
||||
|
||||
except:
|
||||
# Else get cryptlib PRNG
|
||||
if cryptlibpyLoaded:
|
||||
def getRandomBytes(howMany):
|
||||
randomKey = cryptlib_py.cryptCreateContext(cryptlib_py.CRYPT_UNUSED,
|
||||
cryptlib_py.CRYPT_ALGO_AES)
|
||||
cryptlib_py.cryptSetAttribute(randomKey,
|
||||
cryptlib_py.CRYPT_CTXINFO_MODE,
|
||||
cryptlib_py.CRYPT_MODE_OFB)
|
||||
cryptlib_py.cryptGenerateKey(randomKey)
|
||||
bytes = createByteArrayZeros(howMany)
|
||||
cryptlib_py.cryptEncrypt(randomKey, bytes)
|
||||
return bytes
|
||||
prngName = "cryptlib"
|
||||
|
||||
else:
|
||||
#Else get UNIX /dev/urandom PRNG
|
||||
try:
|
||||
devRandomFile = open("/dev/urandom", "rb")
|
||||
def getRandomBytes(howMany):
|
||||
return stringToBytes(devRandomFile.read(howMany))
|
||||
prngName = "/dev/urandom"
|
||||
except IOError:
|
||||
#Else get Win32 CryptoAPI PRNG
|
||||
try:
|
||||
import win32prng
|
||||
def getRandomBytes(howMany):
|
||||
s = win32prng.getRandomBytes(howMany)
|
||||
if len(s) != howMany:
|
||||
raise AssertionError()
|
||||
return stringToBytes(s)
|
||||
prngName ="CryptoAPI"
|
||||
except ImportError:
|
||||
#Else no PRNG :-(
|
||||
def getRandomBytes(howMany):
|
||||
raise NotImplementedError("No Random Number Generator "\
|
||||
"available.")
|
||||
prngName = "None"
|
||||
|
||||
# **************************************************************************
|
||||
# Converter Functions
|
||||
# **************************************************************************
|
||||
|
||||
def bytesToNumber(bytes):
|
||||
total = 0L
|
||||
multiplier = 1L
|
||||
for count in range(len(bytes)-1, -1, -1):
|
||||
byte = bytes[count]
|
||||
total += multiplier * byte
|
||||
multiplier *= 256
|
||||
return total
|
||||
|
||||
def numberToBytes(n):
|
||||
howManyBytes = numBytes(n)
|
||||
bytes = createByteArrayZeros(howManyBytes)
|
||||
for count in range(howManyBytes-1, -1, -1):
|
||||
bytes[count] = int(n % 256)
|
||||
n >>= 8
|
||||
return bytes
|
||||
|
||||
def bytesToBase64(bytes):
|
||||
s = bytesToString(bytes)
|
||||
return stringToBase64(s)
|
||||
|
||||
def base64ToBytes(s):
|
||||
s = base64ToString(s)
|
||||
return stringToBytes(s)
|
||||
|
||||
def numberToBase64(n):
|
||||
bytes = numberToBytes(n)
|
||||
return bytesToBase64(bytes)
|
||||
|
||||
def base64ToNumber(s):
|
||||
bytes = base64ToBytes(s)
|
||||
return bytesToNumber(bytes)
|
||||
|
||||
def stringToNumber(s):
|
||||
bytes = stringToBytes(s)
|
||||
return bytesToNumber(bytes)
|
||||
|
||||
def numberToString(s):
|
||||
bytes = numberToBytes(s)
|
||||
return bytesToString(bytes)
|
||||
|
||||
def base64ToString(s):
|
||||
try:
|
||||
return base64.decodestring(s)
|
||||
except binascii.Error, e:
|
||||
raise SyntaxError(e)
|
||||
except binascii.Incomplete, e:
|
||||
raise SyntaxError(e)
|
||||
|
||||
def stringToBase64(s):
|
||||
return base64.encodestring(s).replace("\n", "")
|
||||
|
||||
def mpiToNumber(mpi): #mpi is an openssl-format bignum string
|
||||
if (ord(mpi[4]) & 0x80) !=0: #Make sure this is a positive number
|
||||
raise AssertionError()
|
||||
bytes = stringToBytes(mpi[4:])
|
||||
return bytesToNumber(bytes)
|
||||
|
||||
def numberToMPI(n):
|
||||
bytes = numberToBytes(n)
|
||||
ext = 0
|
||||
#If the high-order bit is going to be set,
|
||||
#add an extra byte of zeros
|
||||
if (numBits(n) & 0x7)==0:
|
||||
ext = 1
|
||||
length = numBytes(n) + ext
|
||||
bytes = concatArrays(createByteArrayZeros(4+ext), bytes)
|
||||
bytes[0] = (length >> 24) & 0xFF
|
||||
bytes[1] = (length >> 16) & 0xFF
|
||||
bytes[2] = (length >> 8) & 0xFF
|
||||
bytes[3] = length & 0xFF
|
||||
return bytesToString(bytes)
|
||||
|
||||
|
||||
|
||||
# **************************************************************************
|
||||
# Misc. Utility Functions
|
||||
# **************************************************************************
|
||||
|
||||
def numBytes(n):
|
||||
if n==0:
|
||||
return 0
|
||||
bits = numBits(n)
|
||||
return int(math.ceil(bits / 8.0))
|
||||
|
||||
def hashAndBase64(s):
|
||||
return stringToBase64(sha1(s).digest())
|
||||
|
||||
def getBase64Nonce(numChars=22): #defaults to an 132 bit nonce
|
||||
bytes = getRandomBytes(numChars)
|
||||
bytesStr = "".join([chr(b) for b in bytes])
|
||||
return stringToBase64(bytesStr)[:numChars]
|
||||
|
||||
|
||||
# **************************************************************************
|
||||
# Big Number Math
|
||||
# **************************************************************************
|
||||
|
||||
def getRandomNumber(low, high):
|
||||
if low >= high:
|
||||
raise AssertionError()
|
||||
howManyBits = numBits(high)
|
||||
howManyBytes = numBytes(high)
|
||||
lastBits = howManyBits % 8
|
||||
while 1:
|
||||
bytes = getRandomBytes(howManyBytes)
|
||||
if lastBits:
|
||||
bytes[0] = bytes[0] % (1 << lastBits)
|
||||
n = bytesToNumber(bytes)
|
||||
if n >= low and n < high:
|
||||
return n
|
||||
|
||||
def gcd(a,b):
|
||||
a, b = max(a,b), min(a,b)
|
||||
while b:
|
||||
a, b = b, a % b
|
||||
return a
|
||||
|
||||
def lcm(a, b):
|
||||
#This will break when python division changes, but we can't use // cause
|
||||
#of Jython
|
||||
return (a * b) / gcd(a, b)
|
||||
|
||||
#Returns inverse of a mod b, zero if none
|
||||
#Uses Extended Euclidean Algorithm
|
||||
def invMod(a, b):
|
||||
c, d = a, b
|
||||
uc, ud = 1, 0
|
||||
while c != 0:
|
||||
#This will break when python division changes, but we can't use //
|
||||
#cause of Jython
|
||||
q = d / c
|
||||
c, d = d-(q*c), c
|
||||
uc, ud = ud - (q * uc), uc
|
||||
if d == 1:
|
||||
return ud % b
|
||||
return 0
|
||||
|
||||
|
||||
if gmpyLoaded:
|
||||
def powMod(base, power, modulus):
|
||||
base = gmpy.mpz(base)
|
||||
power = gmpy.mpz(power)
|
||||
modulus = gmpy.mpz(modulus)
|
||||
result = pow(base, power, modulus)
|
||||
return long(result)
|
||||
|
||||
else:
|
||||
#Copied from Bryan G. Olson's post to comp.lang.python
|
||||
#Does left-to-right instead of pow()'s right-to-left,
|
||||
#thus about 30% faster than the python built-in with small bases
|
||||
def powMod(base, power, modulus):
|
||||
nBitScan = 5
|
||||
|
||||
""" Return base**power mod modulus, using multi bit scanning
|
||||
with nBitScan bits at a time."""
|
||||
|
||||
#TREV - Added support for negative exponents
|
||||
negativeResult = False
|
||||
if (power < 0):
|
||||
power *= -1
|
||||
negativeResult = True
|
||||
|
||||
exp2 = 2**nBitScan
|
||||
mask = exp2 - 1
|
||||
|
||||
# Break power into a list of digits of nBitScan bits.
|
||||
# The list is recursive so easy to read in reverse direction.
|
||||
nibbles = None
|
||||
while power:
|
||||
nibbles = int(power & mask), nibbles
|
||||
power = power >> nBitScan
|
||||
|
||||
# Make a table of powers of base up to 2**nBitScan - 1
|
||||
lowPowers = [1]
|
||||
for i in xrange(1, exp2):
|
||||
lowPowers.append((lowPowers[i-1] * base) % modulus)
|
||||
|
||||
# To exponentiate by the first nibble, look it up in the table
|
||||
nib, nibbles = nibbles
|
||||
prod = lowPowers[nib]
|
||||
|
||||
# For the rest, square nBitScan times, then multiply by
|
||||
# base^nibble
|
||||
while nibbles:
|
||||
nib, nibbles = nibbles
|
||||
for i in xrange(nBitScan):
|
||||
prod = (prod * prod) % modulus
|
||||
if nib: prod = (prod * lowPowers[nib]) % modulus
|
||||
|
||||
#TREV - Added support for negative exponents
|
||||
if negativeResult:
|
||||
prodInv = invMod(prod, modulus)
|
||||
#Check to make sure the inverse is correct
|
||||
if (prod * prodInv) % modulus != 1:
|
||||
raise AssertionError()
|
||||
return prodInv
|
||||
return prod
|
||||
|
||||
|
||||
#Pre-calculate a sieve of the ~100 primes < 1000:
|
||||
def makeSieve(n):
|
||||
sieve = range(n)
|
||||
for count in range(2, int(math.sqrt(n))):
|
||||
if sieve[count] == 0:
|
||||
continue
|
||||
x = sieve[count] * 2
|
||||
while x < len(sieve):
|
||||
sieve[x] = 0
|
||||
x += sieve[count]
|
||||
sieve = [x for x in sieve[2:] if x]
|
||||
return sieve
|
||||
|
||||
sieve = makeSieve(1000)
|
||||
|
||||
def isPrime(n, iterations=5, display=False):
|
||||
#Trial division with sieve
|
||||
for x in sieve:
|
||||
if x >= n: return True
|
||||
if n % x == 0: return False
|
||||
#Passed trial division, proceed to Rabin-Miller
|
||||
#Rabin-Miller implemented per Ferguson & Schneier
|
||||
#Compute s, t for Rabin-Miller
|
||||
if display: print "*",
|
||||
s, t = n-1, 0
|
||||
while s % 2 == 0:
|
||||
s, t = s/2, t+1
|
||||
#Repeat Rabin-Miller x times
|
||||
a = 2 #Use 2 as a base for first iteration speedup, per HAC
|
||||
for count in range(iterations):
|
||||
v = powMod(a, s, n)
|
||||
if v==1:
|
||||
continue
|
||||
i = 0
|
||||
while v != n-1:
|
||||
if i == t-1:
|
||||
return False
|
||||
else:
|
||||
v, i = powMod(v, 2, n), i+1
|
||||
a = getRandomNumber(2, n)
|
||||
return True
|
||||
|
||||
def getRandomPrime(bits, display=False):
|
||||
if bits < 10:
|
||||
raise AssertionError()
|
||||
#The 1.5 ensures the 2 MSBs are set
|
||||
#Thus, when used for p,q in RSA, n will have its MSB set
|
||||
#
|
||||
#Since 30 is lcm(2,3,5), we'll set our test numbers to
|
||||
#29 % 30 and keep them there
|
||||
low = (2L ** (bits-1)) * 3/2
|
||||
high = 2L ** bits - 30
|
||||
p = getRandomNumber(low, high)
|
||||
p += 29 - (p % 30)
|
||||
while 1:
|
||||
if display: print ".",
|
||||
p += 30
|
||||
if p >= high:
|
||||
p = getRandomNumber(low, high)
|
||||
p += 29 - (p % 30)
|
||||
if isPrime(p, display=display):
|
||||
return p
|
||||
|
||||
#Unused at the moment...
|
||||
def getRandomSafePrime(bits, display=False):
|
||||
if bits < 10:
|
||||
raise AssertionError()
|
||||
#The 1.5 ensures the 2 MSBs are set
|
||||
#Thus, when used for p,q in RSA, n will have its MSB set
|
||||
#
|
||||
#Since 30 is lcm(2,3,5), we'll set our test numbers to
|
||||
#29 % 30 and keep them there
|
||||
low = (2 ** (bits-2)) * 3/2
|
||||
high = (2 ** (bits-1)) - 30
|
||||
q = getRandomNumber(low, high)
|
||||
q += 29 - (q % 30)
|
||||
while 1:
|
||||
if display: print ".",
|
||||
q += 30
|
||||
if (q >= high):
|
||||
q = getRandomNumber(low, high)
|
||||
q += 29 - (q % 30)
|
||||
#Ideas from Tom Wu's SRP code
|
||||
#Do trial division on p and q before Rabin-Miller
|
||||
if isPrime(q, 0, display=display):
|
||||
p = (2 * q) + 1
|
||||
if isPrime(p, display=display):
|
||||
if isPrime(q, display=display):
|
||||
return p
|
75
python/gdata/tlslite/utils/dateFuncs.py
Normal file
75
python/gdata/tlslite/utils/dateFuncs.py
Normal file
@@ -0,0 +1,75 @@
|
||||
|
||||
import os
|
||||
|
||||
#Functions for manipulating datetime objects
|
||||
#CCYY-MM-DDThh:mm:ssZ
|
||||
def parseDateClass(s):
|
||||
year, month, day = s.split("-")
|
||||
day, tail = day[:2], day[2:]
|
||||
hour, minute, second = tail[1:].split(":")
|
||||
second = second[:2]
|
||||
year, month, day = int(year), int(month), int(day)
|
||||
hour, minute, second = int(hour), int(minute), int(second)
|
||||
return createDateClass(year, month, day, hour, minute, second)
|
||||
|
||||
|
||||
if os.name != "java":
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
#Helper functions for working with a date/time class
|
||||
def createDateClass(year, month, day, hour, minute, second):
|
||||
return datetime(year, month, day, hour, minute, second)
|
||||
|
||||
def printDateClass(d):
|
||||
#Split off fractional seconds, append 'Z'
|
||||
return d.isoformat().split(".")[0]+"Z"
|
||||
|
||||
def getNow():
|
||||
return datetime.utcnow()
|
||||
|
||||
def getHoursFromNow(hours):
|
||||
return datetime.utcnow() + timedelta(hours=hours)
|
||||
|
||||
def getMinutesFromNow(minutes):
|
||||
return datetime.utcnow() + timedelta(minutes=minutes)
|
||||
|
||||
def isDateClassExpired(d):
|
||||
return d < datetime.utcnow()
|
||||
|
||||
def isDateClassBefore(d1, d2):
|
||||
return d1 < d2
|
||||
|
||||
else:
|
||||
#Jython 2.1 is missing lots of python 2.3 stuff,
|
||||
#which we have to emulate here:
|
||||
import java
|
||||
import jarray
|
||||
|
||||
def createDateClass(year, month, day, hour, minute, second):
|
||||
c = java.util.Calendar.getInstance()
|
||||
c.setTimeZone(java.util.TimeZone.getTimeZone("UTC"))
|
||||
c.set(year, month-1, day, hour, minute, second)
|
||||
return c
|
||||
|
||||
def printDateClass(d):
|
||||
return "%04d-%02d-%02dT%02d:%02d:%02dZ" % \
|
||||
(d.get(d.YEAR), d.get(d.MONTH)+1, d.get(d.DATE), \
|
||||
d.get(d.HOUR_OF_DAY), d.get(d.MINUTE), d.get(d.SECOND))
|
||||
|
||||
def getNow():
|
||||
c = java.util.Calendar.getInstance()
|
||||
c.setTimeZone(java.util.TimeZone.getTimeZone("UTC"))
|
||||
c.get(c.HOUR) #force refresh?
|
||||
return c
|
||||
|
||||
def getHoursFromNow(hours):
|
||||
d = getNow()
|
||||
d.add(d.HOUR, hours)
|
||||
return d
|
||||
|
||||
def isDateClassExpired(d):
|
||||
n = getNow()
|
||||
return d.before(n)
|
||||
|
||||
def isDateClassBefore(d1, d2):
|
||||
return d1.before(d2)
|
104
python/gdata/tlslite/utils/hmac.py
Normal file
104
python/gdata/tlslite/utils/hmac.py
Normal file
@@ -0,0 +1,104 @@
|
||||
"""HMAC (Keyed-Hashing for Message Authentication) Python module.
|
||||
|
||||
Implements the HMAC algorithm as described by RFC 2104.
|
||||
|
||||
(This file is modified from the standard library version to do faster
|
||||
copying)
|
||||
"""
|
||||
|
||||
def _strxor(s1, s2):
|
||||
"""Utility method. XOR the two strings s1 and s2 (must have same length).
|
||||
"""
|
||||
return "".join(map(lambda x, y: chr(ord(x) ^ ord(y)), s1, s2))
|
||||
|
||||
# The size of the digests returned by HMAC depends on the underlying
|
||||
# hashing module used.
|
||||
digest_size = None
|
||||
|
||||
class HMAC:
|
||||
"""RFC2104 HMAC class.
|
||||
|
||||
This supports the API for Cryptographic Hash Functions (PEP 247).
|
||||
"""
|
||||
|
||||
def __init__(self, key, msg = None, digestmod = None):
|
||||
"""Create a new HMAC object.
|
||||
|
||||
key: key for the keyed hash object.
|
||||
msg: Initial input for the hash, if provided.
|
||||
digestmod: A module supporting PEP 247. Defaults to the md5 module.
|
||||
"""
|
||||
if digestmod is None:
|
||||
import md5
|
||||
digestmod = md5
|
||||
|
||||
if key == None: #TREVNEW - for faster copying
|
||||
return #TREVNEW
|
||||
|
||||
self.digestmod = digestmod
|
||||
self.outer = digestmod.new()
|
||||
self.inner = digestmod.new()
|
||||
self.digest_size = digestmod.digest_size
|
||||
|
||||
blocksize = 64
|
||||
ipad = "\x36" * blocksize
|
||||
opad = "\x5C" * blocksize
|
||||
|
||||
if len(key) > blocksize:
|
||||
key = digestmod.new(key).digest()
|
||||
|
||||
key = key + chr(0) * (blocksize - len(key))
|
||||
self.outer.update(_strxor(key, opad))
|
||||
self.inner.update(_strxor(key, ipad))
|
||||
if msg is not None:
|
||||
self.update(msg)
|
||||
|
||||
## def clear(self):
|
||||
## raise NotImplementedError, "clear() method not available in HMAC."
|
||||
|
||||
def update(self, msg):
|
||||
"""Update this hashing object with the string msg.
|
||||
"""
|
||||
self.inner.update(msg)
|
||||
|
||||
def copy(self):
|
||||
"""Return a separate copy of this hashing object.
|
||||
|
||||
An update to this copy won't affect the original object.
|
||||
"""
|
||||
other = HMAC(None) #TREVNEW - for faster copying
|
||||
other.digest_size = self.digest_size #TREVNEW
|
||||
other.digestmod = self.digestmod
|
||||
other.inner = self.inner.copy()
|
||||
other.outer = self.outer.copy()
|
||||
return other
|
||||
|
||||
def digest(self):
|
||||
"""Return the hash value of this hashing object.
|
||||
|
||||
This returns a string containing 8-bit data. The object is
|
||||
not altered in any way by this function; you can continue
|
||||
updating the object after calling this function.
|
||||
"""
|
||||
h = self.outer.copy()
|
||||
h.update(self.inner.digest())
|
||||
return h.digest()
|
||||
|
||||
def hexdigest(self):
|
||||
"""Like digest(), but returns a string of hexadecimal digits instead.
|
||||
"""
|
||||
return "".join([hex(ord(x))[2:].zfill(2)
|
||||
for x in tuple(self.digest())])
|
||||
|
||||
def new(key, msg = None, digestmod = None):
|
||||
"""Create a new hashing object and return it.
|
||||
|
||||
key: The starting key for the hash.
|
||||
msg: if available, will immediately be hashed into the object's starting
|
||||
state.
|
||||
|
||||
You can now feed arbitrary strings into the object using its update()
|
||||
method, and can ask for the hash value at any time by calling its digest()
|
||||
method.
|
||||
"""
|
||||
return HMAC(key, msg, digestmod)
|
195
python/gdata/tlslite/utils/jython_compat.py
Normal file
195
python/gdata/tlslite/utils/jython_compat.py
Normal file
@@ -0,0 +1,195 @@
|
||||
"""Miscellaneous functions to mask Python/Jython differences."""
|
||||
|
||||
import os
|
||||
import sha
|
||||
|
||||
if os.name != "java":
|
||||
BaseException = Exception
|
||||
|
||||
from sets import Set
|
||||
import array
|
||||
import math
|
||||
|
||||
def createByteArraySequence(seq):
|
||||
return array.array('B', seq)
|
||||
def createByteArrayZeros(howMany):
|
||||
return array.array('B', [0] * howMany)
|
||||
def concatArrays(a1, a2):
|
||||
return a1+a2
|
||||
|
||||
def bytesToString(bytes):
|
||||
return bytes.tostring()
|
||||
|
||||
def stringToBytes(s):
|
||||
bytes = createByteArrayZeros(0)
|
||||
bytes.fromstring(s)
|
||||
return bytes
|
||||
|
||||
def numBits(n):
|
||||
if n==0:
|
||||
return 0
|
||||
return int(math.floor(math.log(n, 2))+1)
|
||||
|
||||
class CertChainBase: pass
|
||||
class SelfTestBase: pass
|
||||
class ReportFuncBase: pass
|
||||
|
||||
#Helper functions for working with sets (from Python 2.3)
|
||||
def iterSet(set):
|
||||
return iter(set)
|
||||
|
||||
def getListFromSet(set):
|
||||
return list(set)
|
||||
|
||||
#Factory function for getting a SHA1 object
|
||||
def getSHA1(s):
|
||||
return sha.sha(s)
|
||||
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
def formatExceptionTrace(e):
|
||||
newStr = "".join(traceback.format_exception(sys.exc_type, sys.exc_value, sys.exc_traceback))
|
||||
return newStr
|
||||
|
||||
else:
|
||||
#Jython 2.1 is missing lots of python 2.3 stuff,
|
||||
#which we have to emulate here:
|
||||
import java
|
||||
import jarray
|
||||
|
||||
BaseException = java.lang.Exception
|
||||
|
||||
def createByteArraySequence(seq):
|
||||
if isinstance(seq, type("")): #If it's a string, convert
|
||||
seq = [ord(c) for c in seq]
|
||||
return jarray.array(seq, 'h') #use short instead of bytes, cause bytes are signed
|
||||
def createByteArrayZeros(howMany):
|
||||
return jarray.zeros(howMany, 'h') #use short instead of bytes, cause bytes are signed
|
||||
def concatArrays(a1, a2):
|
||||
l = list(a1)+list(a2)
|
||||
return createByteArraySequence(l)
|
||||
|
||||
#WAY TOO SLOW - MUST BE REPLACED------------
|
||||
def bytesToString(bytes):
|
||||
return "".join([chr(b) for b in bytes])
|
||||
|
||||
def stringToBytes(s):
|
||||
bytes = createByteArrayZeros(len(s))
|
||||
for count, c in enumerate(s):
|
||||
bytes[count] = ord(c)
|
||||
return bytes
|
||||
#WAY TOO SLOW - MUST BE REPLACED------------
|
||||
|
||||
def numBits(n):
|
||||
if n==0:
|
||||
return 0
|
||||
n= 1L * n; #convert to long, if it isn't already
|
||||
return n.__tojava__(java.math.BigInteger).bitLength()
|
||||
|
||||
#This properly creates static methods for Jython
|
||||
class staticmethod:
|
||||
def __init__(self, anycallable): self.__call__ = anycallable
|
||||
|
||||
#Properties are not supported for Jython
|
||||
class property:
|
||||
def __init__(self, anycallable): pass
|
||||
|
||||
#True and False have to be specially defined
|
||||
False = 0
|
||||
True = 1
|
||||
|
||||
class StopIteration(Exception): pass
|
||||
|
||||
def enumerate(collection):
|
||||
return zip(range(len(collection)), collection)
|
||||
|
||||
class Set:
|
||||
def __init__(self, seq=None):
|
||||
self.values = {}
|
||||
if seq:
|
||||
for e in seq:
|
||||
self.values[e] = None
|
||||
|
||||
def add(self, e):
|
||||
self.values[e] = None
|
||||
|
||||
def discard(self, e):
|
||||
if e in self.values.keys():
|
||||
del(self.values[e])
|
||||
|
||||
def union(self, s):
|
||||
ret = Set()
|
||||
for e in self.values.keys():
|
||||
ret.values[e] = None
|
||||
for e in s.values.keys():
|
||||
ret.values[e] = None
|
||||
return ret
|
||||
|
||||
def issubset(self, other):
|
||||
for e in self.values.keys():
|
||||
if e not in other.values.keys():
|
||||
return False
|
||||
return True
|
||||
|
||||
def __nonzero__( self):
|
||||
return len(self.values.keys())
|
||||
|
||||
def __contains__(self, e):
|
||||
return e in self.values.keys()
|
||||
|
||||
def iterSet(set):
|
||||
return set.values.keys()
|
||||
|
||||
def getListFromSet(set):
|
||||
return set.values.keys()
|
||||
|
||||
"""
|
||||
class JCE_SHA1:
|
||||
def __init__(self, s=None):
|
||||
self.md = java.security.MessageDigest.getInstance("SHA1")
|
||||
if s:
|
||||
self.update(s)
|
||||
|
||||
def update(self, s):
|
||||
self.md.update(s)
|
||||
|
||||
def copy(self):
|
||||
sha1 = JCE_SHA1()
|
||||
sha1.md = self.md.clone()
|
||||
return sha1
|
||||
|
||||
def digest(self):
|
||||
digest = self.md.digest()
|
||||
bytes = jarray.zeros(20, 'h')
|
||||
for count in xrange(20):
|
||||
x = digest[count]
|
||||
if x < 0: x += 256
|
||||
bytes[count] = x
|
||||
return bytes
|
||||
"""
|
||||
|
||||
#Factory function for getting a SHA1 object
|
||||
#The JCE_SHA1 class is way too slow...
|
||||
#the sha.sha object we use instead is broken in the jython 2.1
|
||||
#release, and needs to be patched
|
||||
def getSHA1(s):
|
||||
#return JCE_SHA1(s)
|
||||
return sha.sha(s)
|
||||
|
||||
|
||||
#Adjust the string to an array of bytes
|
||||
def stringToJavaByteArray(s):
|
||||
bytes = jarray.zeros(len(s), 'b')
|
||||
for count, c in enumerate(s):
|
||||
x = ord(c)
|
||||
if x >= 128: x -= 256
|
||||
bytes[count] = x
|
||||
return bytes
|
||||
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
def formatExceptionTrace(e):
|
||||
newStr = "".join(traceback.format_exception(sys.exc_type, sys.exc_value, sys.exc_traceback))
|
||||
return newStr
|
243
python/gdata/tlslite/utils/keyfactory.py
Normal file
243
python/gdata/tlslite/utils/keyfactory.py
Normal file
@@ -0,0 +1,243 @@
|
||||
"""Factory functions for asymmetric cryptography.
|
||||
@sort: generateRSAKey, parseXMLKey, parsePEMKey, parseAsPublicKey,
|
||||
parseAsPrivateKey
|
||||
"""
|
||||
|
||||
from compat import *
|
||||
|
||||
from RSAKey import RSAKey
|
||||
from Python_RSAKey import Python_RSAKey
|
||||
import cryptomath
|
||||
|
||||
if cryptomath.m2cryptoLoaded:
|
||||
from OpenSSL_RSAKey import OpenSSL_RSAKey
|
||||
|
||||
if cryptomath.pycryptoLoaded:
|
||||
from PyCrypto_RSAKey import PyCrypto_RSAKey
|
||||
|
||||
# **************************************************************************
|
||||
# Factory Functions for RSA Keys
|
||||
# **************************************************************************
|
||||
|
||||
def generateRSAKey(bits, implementations=["openssl", "python"]):
|
||||
"""Generate an RSA key with the specified bit length.
|
||||
|
||||
@type bits: int
|
||||
@param bits: Desired bit length of the new key's modulus.
|
||||
|
||||
@rtype: L{tlslite.utils.RSAKey.RSAKey}
|
||||
@return: A new RSA private key.
|
||||
"""
|
||||
for implementation in implementations:
|
||||
if implementation == "openssl" and cryptomath.m2cryptoLoaded:
|
||||
return OpenSSL_RSAKey.generate(bits)
|
||||
elif implementation == "python":
|
||||
return Python_RSAKey.generate(bits)
|
||||
raise ValueError("No acceptable implementations")
|
||||
|
||||
def parseXMLKey(s, private=False, public=False, implementations=["python"]):
|
||||
"""Parse an XML-format key.
|
||||
|
||||
The XML format used here is specific to tlslite and cryptoIDlib. The
|
||||
format can store the public component of a key, or the public and
|
||||
private components. For example::
|
||||
|
||||
<publicKey xmlns="http://trevp.net/rsa">
|
||||
<n>4a5yzB8oGNlHo866CAspAC47M4Fvx58zwK8pou...
|
||||
<e>Aw==</e>
|
||||
</publicKey>
|
||||
|
||||
<privateKey xmlns="http://trevp.net/rsa">
|
||||
<n>4a5yzB8oGNlHo866CAspAC47M4Fvx58zwK8pou...
|
||||
<e>Aw==</e>
|
||||
<d>JZ0TIgUxWXmL8KJ0VqyG1V0J3ern9pqIoB0xmy...
|
||||
<p>5PreIj6z6ldIGL1V4+1C36dQFHNCQHJvW52GXc...
|
||||
<q>/E/wDit8YXPCxx126zTq2ilQ3IcW54NJYyNjiZ...
|
||||
<dP>mKc+wX8inDowEH45Qp4slRo1YveBgExKPROu6...
|
||||
<dQ>qDVKtBz9lk0shL5PR3ickXDgkwS576zbl2ztB...
|
||||
<qInv>j6E8EA7dNsTImaXexAmLA1DoeArsYeFAInr...
|
||||
</privateKey>
|
||||
|
||||
@type s: str
|
||||
@param s: A string containing an XML public or private key.
|
||||
|
||||
@type private: bool
|
||||
@param private: If True, a L{SyntaxError} will be raised if the private
|
||||
key component is not present.
|
||||
|
||||
@type public: bool
|
||||
@param public: If True, the private key component (if present) will be
|
||||
discarded, so this function will always return a public key.
|
||||
|
||||
@rtype: L{tlslite.utils.RSAKey.RSAKey}
|
||||
@return: An RSA key.
|
||||
|
||||
@raise SyntaxError: If the key is not properly formatted.
|
||||
"""
|
||||
for implementation in implementations:
|
||||
if implementation == "python":
|
||||
key = Python_RSAKey.parseXML(s)
|
||||
break
|
||||
else:
|
||||
raise ValueError("No acceptable implementations")
|
||||
|
||||
return _parseKeyHelper(key, private, public)
|
||||
|
||||
#Parse as an OpenSSL or Python key
|
||||
def parsePEMKey(s, private=False, public=False, passwordCallback=None,
|
||||
implementations=["openssl", "python"]):
|
||||
"""Parse a PEM-format key.
|
||||
|
||||
The PEM format is used by OpenSSL and other tools. The
|
||||
format is typically used to store both the public and private
|
||||
components of a key. For example::
|
||||
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIICXQIBAAKBgQDYscuoMzsGmW0pAYsmyHltxB2TdwHS0dImfjCMfaSDkfLdZY5+
|
||||
dOWORVns9etWnr194mSGA1F0Pls/VJW8+cX9+3vtJV8zSdANPYUoQf0TP7VlJxkH
|
||||
dSRkUbEoz5bAAs/+970uos7n7iXQIni+3erUTdYEk2iWnMBjTljfgbK/dQIDAQAB
|
||||
AoGAJHoJZk75aKr7DSQNYIHuruOMdv5ZeDuJvKERWxTrVJqE32/xBKh42/IgqRrc
|
||||
esBN9ZregRCd7YtxoL+EVUNWaJNVx2mNmezEznrc9zhcYUrgeaVdFO2yBF1889zO
|
||||
gCOVwrO8uDgeyj6IKa25H6c1N13ih/o7ZzEgWbGG+ylU1yECQQDv4ZSJ4EjSh/Fl
|
||||
aHdz3wbBa/HKGTjC8iRy476Cyg2Fm8MZUe9Yy3udOrb5ZnS2MTpIXt5AF3h2TfYV
|
||||
VoFXIorjAkEA50FcJmzT8sNMrPaV8vn+9W2Lu4U7C+K/O2g1iXMaZms5PC5zV5aV
|
||||
CKXZWUX1fq2RaOzlbQrpgiolhXpeh8FjxwJBAOFHzSQfSsTNfttp3KUpU0LbiVvv
|
||||
i+spVSnA0O4rq79KpVNmK44Mq67hsW1P11QzrzTAQ6GVaUBRv0YS061td1kCQHnP
|
||||
wtN2tboFR6lABkJDjxoGRvlSt4SOPr7zKGgrWjeiuTZLHXSAnCY+/hr5L9Q3ZwXG
|
||||
6x6iBdgLjVIe4BZQNtcCQQDXGv/gWinCNTN3MPWfTW/RGzuMYVmyBFais0/VrgdH
|
||||
h1dLpztmpQqfyH/zrBXQ9qL/zR4ojS6XYneO/U18WpEe
|
||||
-----END RSA PRIVATE KEY-----
|
||||
|
||||
To generate a key like this with OpenSSL, run::
|
||||
|
||||
openssl genrsa 2048 > key.pem
|
||||
|
||||
This format also supports password-encrypted private keys. TLS
|
||||
Lite can only handle password-encrypted private keys when OpenSSL
|
||||
and M2Crypto are installed. In this case, passwordCallback will be
|
||||
invoked to query the user for the password.
|
||||
|
||||
@type s: str
|
||||
@param s: A string containing a PEM-encoded public or private key.
|
||||
|
||||
@type private: bool
|
||||
@param private: If True, a L{SyntaxError} will be raised if the
|
||||
private key component is not present.
|
||||
|
||||
@type public: bool
|
||||
@param public: If True, the private key component (if present) will
|
||||
be discarded, so this function will always return a public key.
|
||||
|
||||
@type passwordCallback: callable
|
||||
@param passwordCallback: This function will be called, with no
|
||||
arguments, if the PEM-encoded private key is password-encrypted.
|
||||
The callback should return the password string. If the password is
|
||||
incorrect, SyntaxError will be raised. If no callback is passed
|
||||
and the key is password-encrypted, a prompt will be displayed at
|
||||
the console.
|
||||
|
||||
@rtype: L{tlslite.utils.RSAKey.RSAKey}
|
||||
@return: An RSA key.
|
||||
|
||||
@raise SyntaxError: If the key is not properly formatted.
|
||||
"""
|
||||
for implementation in implementations:
|
||||
if implementation == "openssl" and cryptomath.m2cryptoLoaded:
|
||||
key = OpenSSL_RSAKey.parse(s, passwordCallback)
|
||||
break
|
||||
elif implementation == "python":
|
||||
key = Python_RSAKey.parsePEM(s)
|
||||
break
|
||||
else:
|
||||
raise ValueError("No acceptable implementations")
|
||||
|
||||
return _parseKeyHelper(key, private, public)
|
||||
|
||||
|
||||
def _parseKeyHelper(key, private, public):
|
||||
if private:
|
||||
if not key.hasPrivateKey():
|
||||
raise SyntaxError("Not a private key!")
|
||||
|
||||
if public:
|
||||
return _createPublicKey(key)
|
||||
|
||||
if private:
|
||||
if hasattr(key, "d"):
|
||||
return _createPrivateKey(key)
|
||||
else:
|
||||
return key
|
||||
|
||||
return key
|
||||
|
||||
def parseAsPublicKey(s):
|
||||
"""Parse an XML or PEM-formatted public key.
|
||||
|
||||
@type s: str
|
||||
@param s: A string containing an XML or PEM-encoded public or private key.
|
||||
|
||||
@rtype: L{tlslite.utils.RSAKey.RSAKey}
|
||||
@return: An RSA public key.
|
||||
|
||||
@raise SyntaxError: If the key is not properly formatted.
|
||||
"""
|
||||
try:
|
||||
return parsePEMKey(s, public=True)
|
||||
except:
|
||||
return parseXMLKey(s, public=True)
|
||||
|
||||
def parsePrivateKey(s):
|
||||
"""Parse an XML or PEM-formatted private key.
|
||||
|
||||
@type s: str
|
||||
@param s: A string containing an XML or PEM-encoded private key.
|
||||
|
||||
@rtype: L{tlslite.utils.RSAKey.RSAKey}
|
||||
@return: An RSA private key.
|
||||
|
||||
@raise SyntaxError: If the key is not properly formatted.
|
||||
"""
|
||||
try:
|
||||
return parsePEMKey(s, private=True)
|
||||
except:
|
||||
return parseXMLKey(s, private=True)
|
||||
|
||||
def _createPublicKey(key):
|
||||
"""
|
||||
Create a new public key. Discard any private component,
|
||||
and return the most efficient key possible.
|
||||
"""
|
||||
if not isinstance(key, RSAKey):
|
||||
raise AssertionError()
|
||||
return _createPublicRSAKey(key.n, key.e)
|
||||
|
||||
def _createPrivateKey(key):
|
||||
"""
|
||||
Create a new private key. Return the most efficient key possible.
|
||||
"""
|
||||
if not isinstance(key, RSAKey):
|
||||
raise AssertionError()
|
||||
if not key.hasPrivateKey():
|
||||
raise AssertionError()
|
||||
return _createPrivateRSAKey(key.n, key.e, key.d, key.p, key.q, key.dP,
|
||||
key.dQ, key.qInv)
|
||||
|
||||
def _createPublicRSAKey(n, e, implementations = ["openssl", "pycrypto",
|
||||
"python"]):
|
||||
for implementation in implementations:
|
||||
if implementation == "openssl" and cryptomath.m2cryptoLoaded:
|
||||
return OpenSSL_RSAKey(n, e)
|
||||
elif implementation == "pycrypto" and cryptomath.pycryptoLoaded:
|
||||
return PyCrypto_RSAKey(n, e)
|
||||
elif implementation == "python":
|
||||
return Python_RSAKey(n, e)
|
||||
raise ValueError("No acceptable implementations")
|
||||
|
||||
def _createPrivateRSAKey(n, e, d, p, q, dP, dQ, qInv,
|
||||
implementations = ["pycrypto", "python"]):
|
||||
for implementation in implementations:
|
||||
if implementation == "pycrypto" and cryptomath.pycryptoLoaded:
|
||||
return PyCrypto_RSAKey(n, e, d, p, q, dP, dQ, qInv)
|
||||
elif implementation == "python":
|
||||
return Python_RSAKey(n, e, d, p, q, dP, dQ, qInv)
|
||||
raise ValueError("No acceptable implementations")
|
392
python/gdata/tlslite/utils/rijndael.py
Normal file
392
python/gdata/tlslite/utils/rijndael.py
Normal file
@@ -0,0 +1,392 @@
|
||||
"""
|
||||
A pure python (slow) implementation of rijndael with a decent interface
|
||||
|
||||
To include -
|
||||
|
||||
from rijndael import rijndael
|
||||
|
||||
To do a key setup -
|
||||
|
||||
r = rijndael(key, block_size = 16)
|
||||
|
||||
key must be a string of length 16, 24, or 32
|
||||
blocksize must be 16, 24, or 32. Default is 16
|
||||
|
||||
To use -
|
||||
|
||||
ciphertext = r.encrypt(plaintext)
|
||||
plaintext = r.decrypt(ciphertext)
|
||||
|
||||
If any strings are of the wrong length a ValueError is thrown
|
||||
"""
|
||||
|
||||
# ported from the Java reference code by Bram Cohen, bram@gawth.com, April 2001
|
||||
# this code is public domain, unless someone makes
|
||||
# an intellectual property claim against the reference
|
||||
# code, in which case it can be made public domain by
|
||||
# deleting all the comments and renaming all the variables
|
||||
|
||||
import copy
|
||||
import string
|
||||
|
||||
|
||||
|
||||
#-----------------------
|
||||
#TREV - ADDED BECAUSE THERE'S WARNINGS ABOUT INT OVERFLOW BEHAVIOR CHANGING IN
|
||||
#2.4.....
|
||||
import os
|
||||
if os.name != "java":
|
||||
import exceptions
|
||||
if hasattr(exceptions, "FutureWarning"):
|
||||
import warnings
|
||||
warnings.filterwarnings("ignore", category=FutureWarning, append=1)
|
||||
#-----------------------
|
||||
|
||||
|
||||
|
||||
shifts = [[[0, 0], [1, 3], [2, 2], [3, 1]],
|
||||
[[0, 0], [1, 5], [2, 4], [3, 3]],
|
||||
[[0, 0], [1, 7], [3, 5], [4, 4]]]
|
||||
|
||||
# [keysize][block_size]
|
||||
num_rounds = {16: {16: 10, 24: 12, 32: 14}, 24: {16: 12, 24: 12, 32: 14}, 32: {16: 14, 24: 14, 32: 14}}
|
||||
|
||||
A = [[1, 1, 1, 1, 1, 0, 0, 0],
|
||||
[0, 1, 1, 1, 1, 1, 0, 0],
|
||||
[0, 0, 1, 1, 1, 1, 1, 0],
|
||||
[0, 0, 0, 1, 1, 1, 1, 1],
|
||||
[1, 0, 0, 0, 1, 1, 1, 1],
|
||||
[1, 1, 0, 0, 0, 1, 1, 1],
|
||||
[1, 1, 1, 0, 0, 0, 1, 1],
|
||||
[1, 1, 1, 1, 0, 0, 0, 1]]
|
||||
|
||||
# produce log and alog tables, needed for multiplying in the
|
||||
# field GF(2^m) (generator = 3)
|
||||
alog = [1]
|
||||
for i in xrange(255):
|
||||
j = (alog[-1] << 1) ^ alog[-1]
|
||||
if j & 0x100 != 0:
|
||||
j ^= 0x11B
|
||||
alog.append(j)
|
||||
|
||||
log = [0] * 256
|
||||
for i in xrange(1, 255):
|
||||
log[alog[i]] = i
|
||||
|
||||
# multiply two elements of GF(2^m)
|
||||
def mul(a, b):
|
||||
if a == 0 or b == 0:
|
||||
return 0
|
||||
return alog[(log[a & 0xFF] + log[b & 0xFF]) % 255]
|
||||
|
||||
# substitution box based on F^{-1}(x)
|
||||
box = [[0] * 8 for i in xrange(256)]
|
||||
box[1][7] = 1
|
||||
for i in xrange(2, 256):
|
||||
j = alog[255 - log[i]]
|
||||
for t in xrange(8):
|
||||
box[i][t] = (j >> (7 - t)) & 0x01
|
||||
|
||||
B = [0, 1, 1, 0, 0, 0, 1, 1]
|
||||
|
||||
# affine transform: box[i] <- B + A*box[i]
|
||||
cox = [[0] * 8 for i in xrange(256)]
|
||||
for i in xrange(256):
|
||||
for t in xrange(8):
|
||||
cox[i][t] = B[t]
|
||||
for j in xrange(8):
|
||||
cox[i][t] ^= A[t][j] * box[i][j]
|
||||
|
||||
# S-boxes and inverse S-boxes
|
||||
S = [0] * 256
|
||||
Si = [0] * 256
|
||||
for i in xrange(256):
|
||||
S[i] = cox[i][0] << 7
|
||||
for t in xrange(1, 8):
|
||||
S[i] ^= cox[i][t] << (7-t)
|
||||
Si[S[i] & 0xFF] = i
|
||||
|
||||
# T-boxes
|
||||
G = [[2, 1, 1, 3],
|
||||
[3, 2, 1, 1],
|
||||
[1, 3, 2, 1],
|
||||
[1, 1, 3, 2]]
|
||||
|
||||
AA = [[0] * 8 for i in xrange(4)]
|
||||
|
||||
for i in xrange(4):
|
||||
for j in xrange(4):
|
||||
AA[i][j] = G[i][j]
|
||||
AA[i][i+4] = 1
|
||||
|
||||
for i in xrange(4):
|
||||
pivot = AA[i][i]
|
||||
if pivot == 0:
|
||||
t = i + 1
|
||||
while AA[t][i] == 0 and t < 4:
|
||||
t += 1
|
||||
assert t != 4, 'G matrix must be invertible'
|
||||
for j in xrange(8):
|
||||
AA[i][j], AA[t][j] = AA[t][j], AA[i][j]
|
||||
pivot = AA[i][i]
|
||||
for j in xrange(8):
|
||||
if AA[i][j] != 0:
|
||||
AA[i][j] = alog[(255 + log[AA[i][j] & 0xFF] - log[pivot & 0xFF]) % 255]
|
||||
for t in xrange(4):
|
||||
if i != t:
|
||||
for j in xrange(i+1, 8):
|
||||
AA[t][j] ^= mul(AA[i][j], AA[t][i])
|
||||
AA[t][i] = 0
|
||||
|
||||
iG = [[0] * 4 for i in xrange(4)]
|
||||
|
||||
for i in xrange(4):
|
||||
for j in xrange(4):
|
||||
iG[i][j] = AA[i][j + 4]
|
||||
|
||||
def mul4(a, bs):
|
||||
if a == 0:
|
||||
return 0
|
||||
r = 0
|
||||
for b in bs:
|
||||
r <<= 8
|
||||
if b != 0:
|
||||
r = r | mul(a, b)
|
||||
return r
|
||||
|
||||
T1 = []
|
||||
T2 = []
|
||||
T3 = []
|
||||
T4 = []
|
||||
T5 = []
|
||||
T6 = []
|
||||
T7 = []
|
||||
T8 = []
|
||||
U1 = []
|
||||
U2 = []
|
||||
U3 = []
|
||||
U4 = []
|
||||
|
||||
for t in xrange(256):
|
||||
s = S[t]
|
||||
T1.append(mul4(s, G[0]))
|
||||
T2.append(mul4(s, G[1]))
|
||||
T3.append(mul4(s, G[2]))
|
||||
T4.append(mul4(s, G[3]))
|
||||
|
||||
s = Si[t]
|
||||
T5.append(mul4(s, iG[0]))
|
||||
T6.append(mul4(s, iG[1]))
|
||||
T7.append(mul4(s, iG[2]))
|
||||
T8.append(mul4(s, iG[3]))
|
||||
|
||||
U1.append(mul4(t, iG[0]))
|
||||
U2.append(mul4(t, iG[1]))
|
||||
U3.append(mul4(t, iG[2]))
|
||||
U4.append(mul4(t, iG[3]))
|
||||
|
||||
# round constants
|
||||
rcon = [1]
|
||||
r = 1
|
||||
for t in xrange(1, 30):
|
||||
r = mul(2, r)
|
||||
rcon.append(r)
|
||||
|
||||
del A
|
||||
del AA
|
||||
del pivot
|
||||
del B
|
||||
del G
|
||||
del box
|
||||
del log
|
||||
del alog
|
||||
del i
|
||||
del j
|
||||
del r
|
||||
del s
|
||||
del t
|
||||
del mul
|
||||
del mul4
|
||||
del cox
|
||||
del iG
|
||||
|
||||
class rijndael:
|
||||
def __init__(self, key, block_size = 16):
|
||||
if block_size != 16 and block_size != 24 and block_size != 32:
|
||||
raise ValueError('Invalid block size: ' + str(block_size))
|
||||
if len(key) != 16 and len(key) != 24 and len(key) != 32:
|
||||
raise ValueError('Invalid key size: ' + str(len(key)))
|
||||
self.block_size = block_size
|
||||
|
||||
ROUNDS = num_rounds[len(key)][block_size]
|
||||
BC = block_size / 4
|
||||
# encryption round keys
|
||||
Ke = [[0] * BC for i in xrange(ROUNDS + 1)]
|
||||
# decryption round keys
|
||||
Kd = [[0] * BC for i in xrange(ROUNDS + 1)]
|
||||
ROUND_KEY_COUNT = (ROUNDS + 1) * BC
|
||||
KC = len(key) / 4
|
||||
|
||||
# copy user material bytes into temporary ints
|
||||
tk = []
|
||||
for i in xrange(0, KC):
|
||||
tk.append((ord(key[i * 4]) << 24) | (ord(key[i * 4 + 1]) << 16) |
|
||||
(ord(key[i * 4 + 2]) << 8) | ord(key[i * 4 + 3]))
|
||||
|
||||
# copy values into round key arrays
|
||||
t = 0
|
||||
j = 0
|
||||
while j < KC and t < ROUND_KEY_COUNT:
|
||||
Ke[t / BC][t % BC] = tk[j]
|
||||
Kd[ROUNDS - (t / BC)][t % BC] = tk[j]
|
||||
j += 1
|
||||
t += 1
|
||||
tt = 0
|
||||
rconpointer = 0
|
||||
while t < ROUND_KEY_COUNT:
|
||||
# extrapolate using phi (the round key evolution function)
|
||||
tt = tk[KC - 1]
|
||||
tk[0] ^= (S[(tt >> 16) & 0xFF] & 0xFF) << 24 ^ \
|
||||
(S[(tt >> 8) & 0xFF] & 0xFF) << 16 ^ \
|
||||
(S[ tt & 0xFF] & 0xFF) << 8 ^ \
|
||||
(S[(tt >> 24) & 0xFF] & 0xFF) ^ \
|
||||
(rcon[rconpointer] & 0xFF) << 24
|
||||
rconpointer += 1
|
||||
if KC != 8:
|
||||
for i in xrange(1, KC):
|
||||
tk[i] ^= tk[i-1]
|
||||
else:
|
||||
for i in xrange(1, KC / 2):
|
||||
tk[i] ^= tk[i-1]
|
||||
tt = tk[KC / 2 - 1]
|
||||
tk[KC / 2] ^= (S[ tt & 0xFF] & 0xFF) ^ \
|
||||
(S[(tt >> 8) & 0xFF] & 0xFF) << 8 ^ \
|
||||
(S[(tt >> 16) & 0xFF] & 0xFF) << 16 ^ \
|
||||
(S[(tt >> 24) & 0xFF] & 0xFF) << 24
|
||||
for i in xrange(KC / 2 + 1, KC):
|
||||
tk[i] ^= tk[i-1]
|
||||
# copy values into round key arrays
|
||||
j = 0
|
||||
while j < KC and t < ROUND_KEY_COUNT:
|
||||
Ke[t / BC][t % BC] = tk[j]
|
||||
Kd[ROUNDS - (t / BC)][t % BC] = tk[j]
|
||||
j += 1
|
||||
t += 1
|
||||
# inverse MixColumn where needed
|
||||
for r in xrange(1, ROUNDS):
|
||||
for j in xrange(BC):
|
||||
tt = Kd[r][j]
|
||||
Kd[r][j] = U1[(tt >> 24) & 0xFF] ^ \
|
||||
U2[(tt >> 16) & 0xFF] ^ \
|
||||
U3[(tt >> 8) & 0xFF] ^ \
|
||||
U4[ tt & 0xFF]
|
||||
self.Ke = Ke
|
||||
self.Kd = Kd
|
||||
|
||||
def encrypt(self, plaintext):
|
||||
if len(plaintext) != self.block_size:
|
||||
raise ValueError('wrong block length, expected ' + str(self.block_size) + ' got ' + str(len(plaintext)))
|
||||
Ke = self.Ke
|
||||
|
||||
BC = self.block_size / 4
|
||||
ROUNDS = len(Ke) - 1
|
||||
if BC == 4:
|
||||
SC = 0
|
||||
elif BC == 6:
|
||||
SC = 1
|
||||
else:
|
||||
SC = 2
|
||||
s1 = shifts[SC][1][0]
|
||||
s2 = shifts[SC][2][0]
|
||||
s3 = shifts[SC][3][0]
|
||||
a = [0] * BC
|
||||
# temporary work array
|
||||
t = []
|
||||
# plaintext to ints + key
|
||||
for i in xrange(BC):
|
||||
t.append((ord(plaintext[i * 4 ]) << 24 |
|
||||
ord(plaintext[i * 4 + 1]) << 16 |
|
||||
ord(plaintext[i * 4 + 2]) << 8 |
|
||||
ord(plaintext[i * 4 + 3]) ) ^ Ke[0][i])
|
||||
# apply round transforms
|
||||
for r in xrange(1, ROUNDS):
|
||||
for i in xrange(BC):
|
||||
a[i] = (T1[(t[ i ] >> 24) & 0xFF] ^
|
||||
T2[(t[(i + s1) % BC] >> 16) & 0xFF] ^
|
||||
T3[(t[(i + s2) % BC] >> 8) & 0xFF] ^
|
||||
T4[ t[(i + s3) % BC] & 0xFF] ) ^ Ke[r][i]
|
||||
t = copy.copy(a)
|
||||
# last round is special
|
||||
result = []
|
||||
for i in xrange(BC):
|
||||
tt = Ke[ROUNDS][i]
|
||||
result.append((S[(t[ i ] >> 24) & 0xFF] ^ (tt >> 24)) & 0xFF)
|
||||
result.append((S[(t[(i + s1) % BC] >> 16) & 0xFF] ^ (tt >> 16)) & 0xFF)
|
||||
result.append((S[(t[(i + s2) % BC] >> 8) & 0xFF] ^ (tt >> 8)) & 0xFF)
|
||||
result.append((S[ t[(i + s3) % BC] & 0xFF] ^ tt ) & 0xFF)
|
||||
return string.join(map(chr, result), '')
|
||||
|
||||
def decrypt(self, ciphertext):
|
||||
if len(ciphertext) != self.block_size:
|
||||
raise ValueError('wrong block length, expected ' + str(self.block_size) + ' got ' + str(len(plaintext)))
|
||||
Kd = self.Kd
|
||||
|
||||
BC = self.block_size / 4
|
||||
ROUNDS = len(Kd) - 1
|
||||
if BC == 4:
|
||||
SC = 0
|
||||
elif BC == 6:
|
||||
SC = 1
|
||||
else:
|
||||
SC = 2
|
||||
s1 = shifts[SC][1][1]
|
||||
s2 = shifts[SC][2][1]
|
||||
s3 = shifts[SC][3][1]
|
||||
a = [0] * BC
|
||||
# temporary work array
|
||||
t = [0] * BC
|
||||
# ciphertext to ints + key
|
||||
for i in xrange(BC):
|
||||
t[i] = (ord(ciphertext[i * 4 ]) << 24 |
|
||||
ord(ciphertext[i * 4 + 1]) << 16 |
|
||||
ord(ciphertext[i * 4 + 2]) << 8 |
|
||||
ord(ciphertext[i * 4 + 3]) ) ^ Kd[0][i]
|
||||
# apply round transforms
|
||||
for r in xrange(1, ROUNDS):
|
||||
for i in xrange(BC):
|
||||
a[i] = (T5[(t[ i ] >> 24) & 0xFF] ^
|
||||
T6[(t[(i + s1) % BC] >> 16) & 0xFF] ^
|
||||
T7[(t[(i + s2) % BC] >> 8) & 0xFF] ^
|
||||
T8[ t[(i + s3) % BC] & 0xFF] ) ^ Kd[r][i]
|
||||
t = copy.copy(a)
|
||||
# last round is special
|
||||
result = []
|
||||
for i in xrange(BC):
|
||||
tt = Kd[ROUNDS][i]
|
||||
result.append((Si[(t[ i ] >> 24) & 0xFF] ^ (tt >> 24)) & 0xFF)
|
||||
result.append((Si[(t[(i + s1) % BC] >> 16) & 0xFF] ^ (tt >> 16)) & 0xFF)
|
||||
result.append((Si[(t[(i + s2) % BC] >> 8) & 0xFF] ^ (tt >> 8)) & 0xFF)
|
||||
result.append((Si[ t[(i + s3) % BC] & 0xFF] ^ tt ) & 0xFF)
|
||||
return string.join(map(chr, result), '')
|
||||
|
||||
def encrypt(key, block):
|
||||
return rijndael(key, len(block)).encrypt(block)
|
||||
|
||||
def decrypt(key, block):
|
||||
return rijndael(key, len(block)).decrypt(block)
|
||||
|
||||
def test():
|
||||
def t(kl, bl):
|
||||
b = 'b' * bl
|
||||
r = rijndael('a' * kl, bl)
|
||||
assert r.decrypt(r.encrypt(b)) == b
|
||||
t(16, 16)
|
||||
t(16, 24)
|
||||
t(16, 32)
|
||||
t(24, 16)
|
||||
t(24, 24)
|
||||
t(24, 32)
|
||||
t(32, 16)
|
||||
t(32, 24)
|
||||
t(32, 32)
|
||||
|
202
python/gdata/tlslite/utils/xmltools.py
Normal file
202
python/gdata/tlslite/utils/xmltools.py
Normal file
@@ -0,0 +1,202 @@
|
||||
"""Helper functions for XML.
|
||||
|
||||
This module has misc. helper functions for working with XML DOM nodes."""
|
||||
|
||||
from compat import *
|
||||
import os
|
||||
import re
|
||||
|
||||
if os.name == "java":
|
||||
# Only for Jython
|
||||
from javax.xml.parsers import *
|
||||
import java
|
||||
|
||||
builder = DocumentBuilderFactory.newInstance().newDocumentBuilder()
|
||||
|
||||
def parseDocument(s):
|
||||
stream = java.io.ByteArrayInputStream(java.lang.String(s).getBytes())
|
||||
return builder.parse(stream)
|
||||
else:
|
||||
from xml.dom import minidom
|
||||
from xml.sax import saxutils
|
||||
|
||||
def parseDocument(s):
|
||||
return minidom.parseString(s)
|
||||
|
||||
def parseAndStripWhitespace(s):
|
||||
try:
|
||||
element = parseDocument(s).documentElement
|
||||
except BaseException, e:
|
||||
raise SyntaxError(str(e))
|
||||
stripWhitespace(element)
|
||||
return element
|
||||
|
||||
#Goes through a DOM tree and removes whitespace besides child elements,
|
||||
#as long as this whitespace is correctly tab-ified
|
||||
def stripWhitespace(element, tab=0):
|
||||
element.normalize()
|
||||
|
||||
lastSpacer = "\n" + ("\t"*tab)
|
||||
spacer = lastSpacer + "\t"
|
||||
|
||||
#Zero children aren't allowed (i.e. <empty/>)
|
||||
#This makes writing output simpler, and matches Canonical XML
|
||||
if element.childNodes.length==0: #DON'T DO len(element.childNodes) - doesn't work in Jython
|
||||
raise SyntaxError("Empty XML elements not allowed")
|
||||
|
||||
#If there's a single child, it must be text context
|
||||
if element.childNodes.length==1:
|
||||
if element.firstChild.nodeType == element.firstChild.TEXT_NODE:
|
||||
#If it's an empty element, remove
|
||||
if element.firstChild.data == lastSpacer:
|
||||
element.removeChild(element.firstChild)
|
||||
return
|
||||
#If not text content, give an error
|
||||
elif element.firstChild.nodeType == element.firstChild.ELEMENT_NODE:
|
||||
raise SyntaxError("Bad whitespace under '%s'" % element.tagName)
|
||||
else:
|
||||
raise SyntaxError("Unexpected node type in XML document")
|
||||
|
||||
#Otherwise there's multiple child element
|
||||
child = element.firstChild
|
||||
while child:
|
||||
if child.nodeType == child.ELEMENT_NODE:
|
||||
stripWhitespace(child, tab+1)
|
||||
child = child.nextSibling
|
||||
elif child.nodeType == child.TEXT_NODE:
|
||||
if child == element.lastChild:
|
||||
if child.data != lastSpacer:
|
||||
raise SyntaxError("Bad whitespace under '%s'" % element.tagName)
|
||||
elif child.data != spacer:
|
||||
raise SyntaxError("Bad whitespace under '%s'" % element.tagName)
|
||||
next = child.nextSibling
|
||||
element.removeChild(child)
|
||||
child = next
|
||||
else:
|
||||
raise SyntaxError("Unexpected node type in XML document")
|
||||
|
||||
|
||||
def checkName(element, name):
|
||||
if element.nodeType != element.ELEMENT_NODE:
|
||||
raise SyntaxError("Missing element: '%s'" % name)
|
||||
|
||||
if name == None:
|
||||
return
|
||||
|
||||
if element.tagName != name:
|
||||
raise SyntaxError("Wrong element name: should be '%s', is '%s'" % (name, element.tagName))
|
||||
|
||||
def getChild(element, index, name=None):
|
||||
if element.nodeType != element.ELEMENT_NODE:
|
||||
raise SyntaxError("Wrong node type in getChild()")
|
||||
|
||||
child = element.childNodes.item(index)
|
||||
if child == None:
|
||||
raise SyntaxError("Missing child: '%s'" % name)
|
||||
checkName(child, name)
|
||||
return child
|
||||
|
||||
def getChildIter(element, index):
|
||||
class ChildIter:
|
||||
def __init__(self, element, index):
|
||||
self.element = element
|
||||
self.index = index
|
||||
|
||||
def next(self):
|
||||
if self.index < len(self.element.childNodes):
|
||||
retVal = self.element.childNodes.item(self.index)
|
||||
self.index += 1
|
||||
else:
|
||||
retVal = None
|
||||
return retVal
|
||||
|
||||
def checkEnd(self):
|
||||
if self.index != len(self.element.childNodes):
|
||||
raise SyntaxError("Too many elements under: '%s'" % self.element.tagName)
|
||||
return ChildIter(element, index)
|
||||
|
||||
def getChildOrNone(element, index):
|
||||
if element.nodeType != element.ELEMENT_NODE:
|
||||
raise SyntaxError("Wrong node type in getChild()")
|
||||
child = element.childNodes.item(index)
|
||||
return child
|
||||
|
||||
def getLastChild(element, index, name=None):
|
||||
if element.nodeType != element.ELEMENT_NODE:
|
||||
raise SyntaxError("Wrong node type in getLastChild()")
|
||||
|
||||
child = element.childNodes.item(index)
|
||||
if child == None:
|
||||
raise SyntaxError("Missing child: '%s'" % name)
|
||||
if child != element.lastChild:
|
||||
raise SyntaxError("Too many elements under: '%s'" % element.tagName)
|
||||
checkName(child, name)
|
||||
return child
|
||||
|
||||
#Regular expressions for syntax-checking attribute and element content
|
||||
nsRegEx = "http://trevp.net/cryptoID\Z"
|
||||
cryptoIDRegEx = "([a-km-z3-9]{5}\.){3}[a-km-z3-9]{5}\Z"
|
||||
urlRegEx = "http(s)?://.{1,100}\Z"
|
||||
sha1Base64RegEx = "[A-Za-z0-9+/]{27}=\Z"
|
||||
base64RegEx = "[A-Za-z0-9+/]+={0,4}\Z"
|
||||
certsListRegEx = "(0)?(1)?(2)?(3)?(4)?(5)?(6)?(7)?(8)?(9)?\Z"
|
||||
keyRegEx = "[A-Z]\Z"
|
||||
keysListRegEx = "(A)?(B)?(C)?(D)?(E)?(F)?(G)?(H)?(I)?(J)?(K)?(L)?(M)?(N)?(O)?(P)?(Q)?(R)?(S)?(T)?(U)?(V)?(W)?(X)?(Y)?(Z)?\Z"
|
||||
dateTimeRegEx = "\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\dZ\Z"
|
||||
shortStringRegEx = ".{1,100}\Z"
|
||||
exprRegEx = "[a-zA-Z0-9 ,()]{1,200}\Z"
|
||||
notAfterDeltaRegEx = "0|([1-9][0-9]{0,8})\Z" #A number from 0 to (1 billion)-1
|
||||
booleanRegEx = "(true)|(false)"
|
||||
|
||||
def getReqAttribute(element, attrName, regEx=""):
|
||||
if element.nodeType != element.ELEMENT_NODE:
|
||||
raise SyntaxError("Wrong node type in getReqAttribute()")
|
||||
|
||||
value = element.getAttribute(attrName)
|
||||
if not value:
|
||||
raise SyntaxError("Missing Attribute: " + attrName)
|
||||
if not re.match(regEx, value):
|
||||
raise SyntaxError("Bad Attribute Value for '%s': '%s' " % (attrName, value))
|
||||
element.removeAttribute(attrName)
|
||||
return str(value) #de-unicode it; this is needed for bsddb, for example
|
||||
|
||||
def getAttribute(element, attrName, regEx=""):
|
||||
if element.nodeType != element.ELEMENT_NODE:
|
||||
raise SyntaxError("Wrong node type in getAttribute()")
|
||||
|
||||
value = element.getAttribute(attrName)
|
||||
if value:
|
||||
if not re.match(regEx, value):
|
||||
raise SyntaxError("Bad Attribute Value for '%s': '%s' " % (attrName, value))
|
||||
element.removeAttribute(attrName)
|
||||
return str(value) #de-unicode it; this is needed for bsddb, for example
|
||||
|
||||
def checkNoMoreAttributes(element):
|
||||
if element.nodeType != element.ELEMENT_NODE:
|
||||
raise SyntaxError("Wrong node type in checkNoMoreAttributes()")
|
||||
|
||||
if element.attributes.length!=0:
|
||||
raise SyntaxError("Extra attributes on '%s'" % element.tagName)
|
||||
|
||||
def getText(element, regEx=""):
|
||||
textNode = element.firstChild
|
||||
if textNode == None:
|
||||
raise SyntaxError("Empty element '%s'" % element.tagName)
|
||||
if textNode.nodeType != textNode.TEXT_NODE:
|
||||
raise SyntaxError("Non-text node: '%s'" % element.tagName)
|
||||
if not re.match(regEx, textNode.data):
|
||||
raise SyntaxError("Bad Text Value for '%s': '%s' " % (element.tagName, textNode.data))
|
||||
return str(textNode.data) #de-unicode it; this is needed for bsddb, for example
|
||||
|
||||
#Function for adding tabs to a string
|
||||
def indent(s, steps, ch="\t"):
|
||||
tabs = ch*steps
|
||||
if s[-1] != "\n":
|
||||
s = tabs + s.replace("\n", "\n"+tabs)
|
||||
else:
|
||||
s = tabs + s.replace("\n", "\n"+tabs)
|
||||
s = s[ : -len(tabs)]
|
||||
return s
|
||||
|
||||
def escape(s):
|
||||
return saxutils.escape(s)
|
Reference in New Issue
Block a user