summaryrefslogtreecommitdiffstats
path: root/src/lib/tlslite/utils
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/tlslite/utils')
-rwxr-xr-xsrc/lib/tlslite/utils/AES.py31
-rwxr-xr-xsrc/lib/tlslite/utils/ASN1Parser.py34
-rwxr-xr-xsrc/lib/tlslite/utils/Cryptlib_AES.py34
-rwxr-xr-xsrc/lib/tlslite/utils/Cryptlib_RC4.py28
-rwxr-xr-xsrc/lib/tlslite/utils/Cryptlib_TripleDES.py35
-rwxr-xr-xsrc/lib/tlslite/utils/OpenSSL_AES.py49
-rwxr-xr-xsrc/lib/tlslite/utils/OpenSSL_RC4.py25
-rwxr-xr-xsrc/lib/tlslite/utils/OpenSSL_RSAKey.py148
-rwxr-xr-xsrc/lib/tlslite/utils/OpenSSL_TripleDES.py44
-rwxr-xr-xsrc/lib/tlslite/utils/PyCrypto_AES.py22
-rwxr-xr-xsrc/lib/tlslite/utils/PyCrypto_RC4.py22
-rwxr-xr-xsrc/lib/tlslite/utils/PyCrypto_RSAKey.py61
-rwxr-xr-xsrc/lib/tlslite/utils/PyCrypto_TripleDES.py22
-rwxr-xr-xsrc/lib/tlslite/utils/Python_AES.py68
-rwxr-xr-xsrc/lib/tlslite/utils/Python_RC4.py39
-rwxr-xr-xsrc/lib/tlslite/utils/Python_RSAKey.py209
-rwxr-xr-xsrc/lib/tlslite/utils/RC4.py17
-rwxr-xr-xsrc/lib/tlslite/utils/RSAKey.py264
-rwxr-xr-xsrc/lib/tlslite/utils/TripleDES.py26
-rwxr-xr-xsrc/lib/tlslite/utils/__init__.py31
-rwxr-xr-xsrc/lib/tlslite/utils/cipherfactory.py111
-rwxr-xr-xsrc/lib/tlslite/utils/codec.py94
-rwxr-xr-xsrc/lib/tlslite/utils/compat.py140
-rwxr-xr-xsrc/lib/tlslite/utils/cryptomath.py400
-rwxr-xr-xsrc/lib/tlslite/utils/dateFuncs.py75
-rwxr-xr-xsrc/lib/tlslite/utils/entropy.c173
-rwxr-xr-xsrc/lib/tlslite/utils/hmac.py104
-rwxr-xr-xsrc/lib/tlslite/utils/jython_compat.py195
-rwxr-xr-xsrc/lib/tlslite/utils/keyfactory.py243
-rwxr-xr-xsrc/lib/tlslite/utils/rijndael.py392
-rwxr-xr-xsrc/lib/tlslite/utils/win32prng.c63
-rwxr-xr-xsrc/lib/tlslite/utils/xmltools.py201
32 files changed, 3400 insertions, 0 deletions
diff --git a/src/lib/tlslite/utils/AES.py b/src/lib/tlslite/utils/AES.py
new file mode 100755
index 000000000..8413f4c10
--- /dev/null
+++ b/src/lib/tlslite/utils/AES.py
@@ -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) \ No newline at end of file
diff --git a/src/lib/tlslite/utils/ASN1Parser.py b/src/lib/tlslite/utils/ASN1Parser.py
new file mode 100755
index 000000000..16b50f29c
--- /dev/null
+++ b/src/lib/tlslite/utils/ASN1Parser.py
@@ -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)
diff --git a/src/lib/tlslite/utils/Cryptlib_AES.py b/src/lib/tlslite/utils/Cryptlib_AES.py
new file mode 100755
index 000000000..9e101fc62
--- /dev/null
+++ b/src/lib/tlslite/utils/Cryptlib_AES.py
@@ -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)
diff --git a/src/lib/tlslite/utils/Cryptlib_RC4.py b/src/lib/tlslite/utils/Cryptlib_RC4.py
new file mode 100755
index 000000000..7c6d087b8
--- /dev/null
+++ b/src/lib/tlslite/utils/Cryptlib_RC4.py
@@ -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) \ No newline at end of file
diff --git a/src/lib/tlslite/utils/Cryptlib_TripleDES.py b/src/lib/tlslite/utils/Cryptlib_TripleDES.py
new file mode 100755
index 000000000..a4f8155a0
--- /dev/null
+++ b/src/lib/tlslite/utils/Cryptlib_TripleDES.py
@@ -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) \ No newline at end of file
diff --git a/src/lib/tlslite/utils/OpenSSL_AES.py b/src/lib/tlslite/utils/OpenSSL_AES.py
new file mode 100755
index 000000000..e60679bf5
--- /dev/null
+++ b/src/lib/tlslite/utils/OpenSSL_AES.py
@@ -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
diff --git a/src/lib/tlslite/utils/OpenSSL_RC4.py b/src/lib/tlslite/utils/OpenSSL_RC4.py
new file mode 100755
index 000000000..ac433aad7
--- /dev/null
+++ b/src/lib/tlslite/utils/OpenSSL_RC4.py
@@ -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)
diff --git a/src/lib/tlslite/utils/OpenSSL_RSAKey.py b/src/lib/tlslite/utils/OpenSSL_RSAKey.py
new file mode 100755
index 000000000..fe1a3cd74
--- /dev/null
+++ b/src/lib/tlslite/utils/OpenSSL_RSAKey.py
@@ -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)
diff --git a/src/lib/tlslite/utils/OpenSSL_TripleDES.py b/src/lib/tlslite/utils/OpenSSL_TripleDES.py
new file mode 100755
index 000000000..f5ba16565
--- /dev/null
+++ b/src/lib/tlslite/utils/OpenSSL_TripleDES.py
@@ -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 \ No newline at end of file
diff --git a/src/lib/tlslite/utils/PyCrypto_AES.py b/src/lib/tlslite/utils/PyCrypto_AES.py
new file mode 100755
index 000000000..e38b19d6f
--- /dev/null
+++ b/src/lib/tlslite/utils/PyCrypto_AES.py
@@ -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) \ No newline at end of file
diff --git a/src/lib/tlslite/utils/PyCrypto_RC4.py b/src/lib/tlslite/utils/PyCrypto_RC4.py
new file mode 100755
index 000000000..6c6d86afd
--- /dev/null
+++ b/src/lib/tlslite/utils/PyCrypto_RC4.py
@@ -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) \ No newline at end of file
diff --git a/src/lib/tlslite/utils/PyCrypto_RSAKey.py b/src/lib/tlslite/utils/PyCrypto_RSAKey.py
new file mode 100755
index 000000000..48b5cef03
--- /dev/null
+++ b/src/lib/tlslite/utils/PyCrypto_RSAKey.py
@@ -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)
diff --git a/src/lib/tlslite/utils/PyCrypto_TripleDES.py b/src/lib/tlslite/utils/PyCrypto_TripleDES.py
new file mode 100755
index 000000000..8c22bb80a
--- /dev/null
+++ b/src/lib/tlslite/utils/PyCrypto_TripleDES.py
@@ -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) \ No newline at end of file
diff --git a/src/lib/tlslite/utils/Python_AES.py b/src/lib/tlslite/utils/Python_AES.py
new file mode 100755
index 000000000..657152f89
--- /dev/null
+++ b/src/lib/tlslite/utils/Python_AES.py
@@ -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)
diff --git a/src/lib/tlslite/utils/Python_RC4.py b/src/lib/tlslite/utils/Python_RC4.py
new file mode 100755
index 000000000..56ce5fb2f
--- /dev/null
+++ b/src/lib/tlslite/utils/Python_RC4.py
@@ -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)
diff --git a/src/lib/tlslite/utils/Python_RSAKey.py b/src/lib/tlslite/utils/Python_RSAKey.py
new file mode 100755
index 000000000..2c469b572
--- /dev/null
+++ b/src/lib/tlslite/utils/Python_RSAKey.py
@@ -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)
diff --git a/src/lib/tlslite/utils/RC4.py b/src/lib/tlslite/utils/RC4.py
new file mode 100755
index 000000000..550692327
--- /dev/null
+++ b/src/lib/tlslite/utils/RC4.py
@@ -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() \ No newline at end of file
diff --git a/src/lib/tlslite/utils/RSAKey.py b/src/lib/tlslite/utils/RSAKey.py
new file mode 100755
index 000000000..37c292df5
--- /dev/null
+++ b/src/lib/tlslite/utils/RSAKey.py
@@ -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(sha.sha(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(sha.sha(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
diff --git a/src/lib/tlslite/utils/TripleDES.py b/src/lib/tlslite/utils/TripleDES.py
new file mode 100755
index 000000000..2db45888b
--- /dev/null
+++ b/src/lib/tlslite/utils/TripleDES.py
@@ -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)
diff --git a/src/lib/tlslite/utils/__init__.py b/src/lib/tlslite/utils/__init__.py
new file mode 100755
index 000000000..e96b4bef8
--- /dev/null
+++ b/src/lib/tlslite/utils/__init__.py
@@ -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"]
diff --git a/src/lib/tlslite/utils/cipherfactory.py b/src/lib/tlslite/utils/cipherfactory.py
new file mode 100755
index 000000000..ccbb6b5ff
--- /dev/null
+++ b/src/lib/tlslite/utils/cipherfactory.py
@@ -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() \ No newline at end of file
diff --git a/src/lib/tlslite/utils/codec.py b/src/lib/tlslite/utils/codec.py
new file mode 100755
index 000000000..13022a0b9
--- /dev/null
+++ b/src/lib/tlslite/utils/codec.py
@@ -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() \ No newline at end of file
diff --git a/src/lib/tlslite/utils/compat.py b/src/lib/tlslite/utils/compat.py
new file mode 100755
index 000000000..7d2d9250d
--- /dev/null
+++ b/src/lib/tlslite/utils/compat.py
@@ -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 \ No newline at end of file
diff --git a/src/lib/tlslite/utils/cryptomath.py b/src/lib/tlslite/utils/cryptomath.py
new file mode 100755
index 000000000..51d6dff7c
--- /dev/null
+++ b/src/lib/tlslite/utils/cryptomath.py
@@ -0,0 +1,400 @@
+"""cryptomath module
+
+This module has basic math/crypto code."""
+
+import os
+import math
+import base64
+import binascii
+import sha
+
+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(sha.sha(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
diff --git a/src/lib/tlslite/utils/dateFuncs.py b/src/lib/tlslite/utils/dateFuncs.py
new file mode 100755
index 000000000..38812ebf8
--- /dev/null
+++ b/src/lib/tlslite/utils/dateFuncs.py
@@ -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)
diff --git a/src/lib/tlslite/utils/entropy.c b/src/lib/tlslite/utils/entropy.c
new file mode 100755
index 000000000..c627794d2
--- /dev/null
+++ b/src/lib/tlslite/utils/entropy.c
@@ -0,0 +1,173 @@
+
+#include "Python.h"
+
+
+#ifdef MS_WINDOWS
+
+/* The following #define is not needed on VC6 with the Platform SDK, and it
+may not be needed on VC7, I'm not sure. I don't think it hurts anything.*/
+#define _WIN32_WINNT 0x0400
+
+#include <windows.h>
+
+
+typedef BOOL (WINAPI *CRYPTACQUIRECONTEXTA)(HCRYPTPROV *phProv,\
+ LPCSTR pszContainer, LPCSTR pszProvider, DWORD dwProvType,\
+ DWORD dwFlags );
+typedef BOOL (WINAPI *CRYPTGENRANDOM)(HCRYPTPROV hProv, DWORD dwLen,\
+ BYTE *pbBuffer );
+typedef BOOL (WINAPI *CRYPTRELEASECONTEXT)(HCRYPTPROV hProv,\
+ DWORD dwFlags);
+
+
+static PyObject* entropy(PyObject *self, PyObject *args)
+{
+ int howMany = 0;
+ HINSTANCE hAdvAPI32 = NULL;
+ CRYPTACQUIRECONTEXTA pCryptAcquireContextA = NULL;
+ CRYPTGENRANDOM pCryptGenRandom = NULL;
+ CRYPTRELEASECONTEXT pCryptReleaseContext = NULL;
+ HCRYPTPROV hCryptProv = 0;
+ unsigned char* bytes = NULL;
+ PyObject* returnVal = NULL;
+
+
+ /* Read arguments */
+ if (!PyArg_ParseTuple(args, "i", &howMany))
+ return(NULL);
+
+ /* Obtain handle to the DLL containing CryptoAPI
+ This should not fail */
+ if( (hAdvAPI32 = GetModuleHandle("advapi32.dll")) == NULL) {
+ PyErr_Format(PyExc_SystemError,
+ "Advapi32.dll not found");
+ return NULL;
+ }
+
+ /* Obtain pointers to the CryptoAPI functions
+ This will fail on some early version of Win95 */
+ pCryptAcquireContextA = (CRYPTACQUIRECONTEXTA)GetProcAddress(hAdvAPI32,\
+ "CryptAcquireContextA");
+ pCryptGenRandom = (CRYPTGENRANDOM)GetProcAddress(hAdvAPI32,\
+ "CryptGenRandom");
+ pCryptReleaseContext = (CRYPTRELEASECONTEXT) GetProcAddress(hAdvAPI32,\
+ "CryptReleaseContext");
+ if (pCryptAcquireContextA == NULL || pCryptGenRandom == NULL ||
+ pCryptReleaseContext == NULL) {
+ PyErr_Format(PyExc_NotImplementedError,
+ "CryptoAPI not available on this version of Windows");
+ return NULL;
+ }
+
+ /* Allocate bytes */
+ if ((bytes = (unsigned char*)PyMem_Malloc(howMany)) == NULL)
+ return PyErr_NoMemory();
+
+
+ /* Acquire context */
+ if(!pCryptAcquireContextA(&hCryptProv, NULL, NULL, PROV_RSA_FULL,
+ CRYPT_VERIFYCONTEXT)) {
+ PyErr_Format(PyExc_SystemError,
+ "CryptAcquireContext failed, error %d", GetLastError());
+ PyMem_Free(bytes);
+ return NULL;
+ }
+
+ /* Get random data */
+ if(!pCryptGenRandom(hCryptProv, howMany, bytes)) {
+ PyErr_Format(PyExc_SystemError,
+ "CryptGenRandom failed, error %d", GetLastError());
+ PyMem_Free(bytes);
+ CryptReleaseContext(hCryptProv, 0);
+ return NULL;
+ }
+
+ /* Build return value */
+ returnVal = Py_BuildValue("s#", bytes, howMany);
+ PyMem_Free(bytes);
+
+ /* Release context */
+ if (!pCryptReleaseContext(hCryptProv, 0)) {
+ PyErr_Format(PyExc_SystemError,
+ "CryptReleaseContext failed, error %d", GetLastError());
+ return NULL;
+ }
+
+ return returnVal;
+}
+
+#elif defined(HAVE_UNISTD_H) && defined(HAVE_FCNTL_H)
+
+#include <unistd.h>
+#include <fcntl.h>
+
+static PyObject* entropy(PyObject *self, PyObject *args)
+{
+ int howMany;
+ int fd;
+ unsigned char* bytes = NULL;
+ PyObject* returnVal = NULL;
+
+
+ /* Read arguments */
+ if (!PyArg_ParseTuple(args, "i", &howMany))
+ return(NULL);
+
+ /* Allocate bytes */
+ if ((bytes = (unsigned char*)PyMem_Malloc(howMany)) == NULL)
+ return PyErr_NoMemory();
+
+ /* Open device */
+ if ((fd = open("/dev/urandom", O_RDONLY, 0)) == -1) {
+ PyErr_Format(PyExc_NotImplementedError,
+ "No entropy source found");
+ PyMem_Free(bytes);
+ return NULL;
+ }
+
+ /* Get random data */
+ if (read(fd, bytes, howMany) < howMany) {
+ PyErr_Format(PyExc_SystemError,
+ "Reading from /dev/urandom failed");
+ PyMem_Free(bytes);
+ close(fd);
+ return NULL;
+ }
+
+ /* Build return value */
+ returnVal = Py_BuildValue("s#", bytes, howMany);
+ PyMem_Free(bytes);
+
+ /* Close device */
+ close(fd);
+
+ return returnVal;
+}
+
+#else
+
+static PyObject* entropy(PyObject *self, PyObject *args)
+{
+ PyErr_Format(PyExc_NotImplementedError,
+ "Function not supported");
+ return NULL;
+}
+
+#endif
+
+
+
+/* List of functions exported by this module */
+
+static struct PyMethodDef entropy_functions[] = {
+ {"entropy", (PyCFunction)entropy, METH_VARARGS, "Return a string of random bytes produced by a platform-specific\nentropy source."},
+ {NULL, NULL} /* Sentinel */
+};
+
+
+/* Initialize this module. */
+
+PyMODINIT_FUNC initentropy(void)
+{
+ Py_InitModule("entropy", entropy_functions);
+} \ No newline at end of file
diff --git a/src/lib/tlslite/utils/hmac.py b/src/lib/tlslite/utils/hmac.py
new file mode 100755
index 000000000..fe8feec21
--- /dev/null
+++ b/src/lib/tlslite/utils/hmac.py
@@ -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)
diff --git a/src/lib/tlslite/utils/jython_compat.py b/src/lib/tlslite/utils/jython_compat.py
new file mode 100755
index 000000000..1245183a9
--- /dev/null
+++ b/src/lib/tlslite/utils/jython_compat.py
@@ -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
diff --git a/src/lib/tlslite/utils/keyfactory.py b/src/lib/tlslite/utils/keyfactory.py
new file mode 100755
index 000000000..5005af7f5
--- /dev/null
+++ b/src/lib/tlslite/utils/keyfactory.py
@@ -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")
diff --git a/src/lib/tlslite/utils/rijndael.py b/src/lib/tlslite/utils/rijndael.py
new file mode 100755
index 000000000..cb2f54734
--- /dev/null
+++ b/src/lib/tlslite/utils/rijndael.py
@@ -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)
+
diff --git a/src/lib/tlslite/utils/win32prng.c b/src/lib/tlslite/utils/win32prng.c
new file mode 100755
index 000000000..de08b3b3b
--- /dev/null
+++ b/src/lib/tlslite/utils/win32prng.c
@@ -0,0 +1,63 @@
+
+#include "Python.h"
+#define _WIN32_WINNT 0x0400 /* Needed for CryptoAPI on some systems */
+#include <windows.h>
+
+
+static PyObject* getRandomBytes(PyObject *self, PyObject *args)
+{
+ int howMany;
+ HCRYPTPROV hCryptProv;
+ unsigned char* bytes = NULL;
+ PyObject* returnVal = NULL;
+
+
+ /* Read Arguments */
+ if (!PyArg_ParseTuple(args, "i", &howMany))
+ return(NULL);
+
+ /* Get Context */
+ if(CryptAcquireContext(
+ &hCryptProv,
+ NULL,
+ NULL,
+ PROV_RSA_FULL,
+ CRYPT_VERIFYCONTEXT) == 0)
+ return Py_BuildValue("s#", NULL, 0);
+
+
+ /* Allocate bytes */
+ bytes = malloc(howMany);
+
+
+ /* Get random data */
+ if(CryptGenRandom(
+ hCryptProv,
+ howMany,
+ bytes) == 0)
+ returnVal = Py_BuildValue("s#", NULL, 0);
+ else
+ returnVal = Py_BuildValue("s#", bytes, howMany);
+
+ free(bytes);
+ CryptReleaseContext(hCryptProv, 0);
+
+ return returnVal;
+}
+
+
+
+/* List of functions exported by this module */
+
+static struct PyMethodDef win32prng_functions[] = {
+ {"getRandomBytes", (PyCFunction)getRandomBytes, METH_VARARGS},
+ {NULL, NULL} /* Sentinel */
+};
+
+
+/* Initialize this module. */
+
+DL_EXPORT(void) initwin32prng(void)
+{
+ Py_InitModule("win32prng", win32prng_functions);
+}
diff --git a/src/lib/tlslite/utils/xmltools.py b/src/lib/tlslite/utils/xmltools.py
new file mode 100755
index 000000000..06f2e4307
--- /dev/null
+++ b/src/lib/tlslite/utils/xmltools.py
@@ -0,0 +1,201 @@
+"""Helper functions for XML.
+
+This module has misc. helper functions for working with XML DOM nodes."""
+
+import re
+from compat import *
+
+import os
+if os.name != "java":
+ from xml.dom import minidom
+ from xml.sax import saxutils
+
+ def parseDocument(s):
+ return minidom.parseString(s)
+else:
+ 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)
+
+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)