Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Unified Diff: third_party/tlslite/patches/aes_gcm.patch

Issue 875683002: Implement AES-GCM in tlslite. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « third_party/tlslite/README.chromium ('k') | third_party/tlslite/tests/tlstest.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/tlslite/patches/aes_gcm.patch
diff --git a/third_party/tlslite/patches/aes_gcm.patch b/third_party/tlslite/patches/aes_gcm.patch
new file mode 100644
index 0000000000000000000000000000000000000000..9d4768dd9919a7f642c97e59af9ef22063966851
--- /dev/null
+++ b/third_party/tlslite/patches/aes_gcm.patch
@@ -0,0 +1,770 @@
+diff --git a/third_party/tlslite/tests/tlstest.py b/third_party/tlslite/tests/tlstest.py
+index fa1b13f..7985d23 100755
+--- a/third_party/tlslite/tests/tlstest.py
++++ b/third_party/tlslite/tests/tlstest.py
+@@ -318,9 +318,11 @@ def clientTestCmd(argv):
+
+ print("Test 23 - throughput test")
+ for implementation in implementations:
+- for cipher in ["aes128", "aes256", "3des", "rc4"]:
++ for cipher in ["aes128gcm", "aes128", "aes256", "3des", "rc4"]:
+ if cipher == "3des" and implementation not in ("openssl", "pycrypto"):
+ continue
++ if cipher == "aes128gcm" and implementation not in ("pycrypto", "python"):
++ continue
+
+ print("Test 23:", end=' ')
+ connection = connect()
+@@ -678,9 +680,11 @@ def serverTestCmd(argv):
+
+ print("Test 23 - throughput test")
+ for implementation in implementations:
+- for cipher in ["aes128", "aes256", "3des", "rc4"]:
++ for cipher in ["aes128gcm", "aes128", "aes256", "3des", "rc4"]:
+ if cipher == "3des" and implementation not in ("openssl", "pycrypto"):
+ continue
++ if cipher == "aes128gcm" and implementation not in ("pycrypto", "python"):
++ continue
+
+ print("Test 23:", end=' ')
+ connection = connect()
+diff --git a/third_party/tlslite/tlslite/constants.py b/third_party/tlslite/tlslite/constants.py
+index 7ee70be..e5b88af 100644
+--- a/third_party/tlslite/tlslite/constants.py
++++ b/third_party/tlslite/tlslite/constants.py
+@@ -175,6 +175,9 @@ class CipherSuite:
+ TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 = 0x0067
+ TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 = 0x006B
+
++ TLS_RSA_WITH_AES_128_GCM_SHA256 = 0x009C
++ TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 = 0x009E
++
+ tripleDESSuites = []
+ tripleDESSuites.append(TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA)
+ tripleDESSuites.append(TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA)
+@@ -199,6 +202,10 @@ class CipherSuite:
+ aes256Suites.append(TLS_RSA_WITH_AES_256_CBC_SHA256)
+ aes256Suites.append(TLS_DHE_RSA_WITH_AES_256_CBC_SHA256)
+
++ aes128GcmSuites = []
++ aes128GcmSuites.append(TLS_RSA_WITH_AES_128_GCM_SHA256)
++ aes128GcmSuites.append(TLS_DHE_RSA_WITH_AES_128_GCM_SHA256)
++
+ rc4Suites = []
+ rc4Suites.append(TLS_RSA_WITH_RC4_128_SHA)
+ rc4Suites.append(TLS_RSA_WITH_RC4_128_MD5)
+@@ -225,25 +232,35 @@ class CipherSuite:
+ sha256Suites.append(TLS_RSA_WITH_AES_256_CBC_SHA256)
+ sha256Suites.append(TLS_DHE_RSA_WITH_AES_128_CBC_SHA256)
+ sha256Suites.append(TLS_DHE_RSA_WITH_AES_256_CBC_SHA256)
++ sha256Suites.append(TLS_RSA_WITH_AES_128_GCM_SHA256)
++ sha256Suites.append(TLS_DHE_RSA_WITH_AES_128_GCM_SHA256)
++
++ aeadSuites = aes128GcmSuites
+
+
+ md5Suites = []
+ md5Suites.append(TLS_RSA_WITH_RC4_128_MD5)
+
+ @staticmethod
+- def _filterSuites(suites, settings):
++ def _filterSuites(suites, settings, version=None):
++ if version is None:
++ version = settings.maxVersion
+ macNames = settings.macNames
+ cipherNames = settings.cipherNames
+ keyExchangeNames = settings.keyExchangeNames
+ macSuites = []
+ if "sha" in macNames:
+ macSuites += CipherSuite.shaSuites
+- if "sha256" in macNames:
++ if "sha256" in macNames and version >= (3,3):
+ macSuites += CipherSuite.sha256Suites
+ if "md5" in macNames:
+ macSuites += CipherSuite.md5Suites
++ if "aead" in macNames and version >= (3,3):
++ macSuites += CipherSuite.aeadSuites
+
+ cipherSuites = []
++ if "aes128gcm" in cipherNames and version >= (3,3):
++ cipherSuites += CipherSuite.aes128GcmSuites
+ if "aes128" in cipherNames:
+ cipherSuites += CipherSuite.aes128Suites
+ if "aes256" in cipherNames:
+@@ -274,8 +291,8 @@ class CipherSuite:
+ srpSuites.append(TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA)
+
+ @staticmethod
+- def getSrpSuites(settings):
+- return CipherSuite._filterSuites(CipherSuite.srpSuites, settings)
++ def getSrpSuites(settings, version=None):
++ return CipherSuite._filterSuites(CipherSuite.srpSuites, settings, version)
+
+ srpCertSuites = []
+ srpCertSuites.append(TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA)
+@@ -283,16 +300,17 @@ class CipherSuite:
+ srpCertSuites.append(TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA)
+
+ @staticmethod
+- def getSrpCertSuites(settings):
+- return CipherSuite._filterSuites(CipherSuite.srpCertSuites, settings)
++ def getSrpCertSuites(settings, version=None):
++ return CipherSuite._filterSuites(CipherSuite.srpCertSuites, settings, version)
+
+ srpAllSuites = srpSuites + srpCertSuites
+
+ @staticmethod
+- def getSrpAllSuites(settings):
+- return CipherSuite._filterSuites(CipherSuite.srpAllSuites, settings)
++ def getSrpAllSuites(settings, version=None):
++ return CipherSuite._filterSuites(CipherSuite.srpAllSuites, settings, version)
+
+ certSuites = []
++ certSuites.append(TLS_RSA_WITH_AES_128_GCM_SHA256)
+ certSuites.append(TLS_RSA_WITH_AES_256_CBC_SHA256)
+ certSuites.append(TLS_RSA_WITH_AES_128_CBC_SHA256)
+ certSuites.append(TLS_RSA_WITH_AES_256_CBC_SHA)
+@@ -302,10 +320,11 @@ class CipherSuite:
+ certSuites.append(TLS_RSA_WITH_RC4_128_MD5)
+
+ @staticmethod
+- def getCertSuites(settings):
+- return CipherSuite._filterSuites(CipherSuite.certSuites, settings)
++ def getCertSuites(settings, version=None):
++ return CipherSuite._filterSuites(CipherSuite.certSuites, settings, version)
+
+ dheCertSuites = []
++ dheCertSuites.append(TLS_DHE_RSA_WITH_AES_128_GCM_SHA256)
+ dheCertSuites.append(TLS_DHE_RSA_WITH_AES_256_CBC_SHA256)
+ dheCertSuites.append(TLS_DHE_RSA_WITH_AES_128_CBC_SHA256)
+ dheCertSuites.append(TLS_DHE_RSA_WITH_AES_256_CBC_SHA)
+@@ -313,8 +332,8 @@ class CipherSuite:
+ dheCertSuites.append(TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA)
+
+ @staticmethod
+- def getDheCertSuites(settings):
+- return CipherSuite._filterSuites(CipherSuite.dheCertSuites, settings)
++ def getDheCertSuites(settings, version=None):
++ return CipherSuite._filterSuites(CipherSuite.dheCertSuites, settings, version)
+
+ certAllSuites = srpCertSuites + certSuites + dheCertSuites
+
+@@ -323,8 +342,8 @@ class CipherSuite:
+ anonSuites.append(TLS_DH_ANON_WITH_AES_128_CBC_SHA)
+
+ @staticmethod
+- def getAnonSuites(settings):
+- return CipherSuite._filterSuites(CipherSuite.anonSuites, settings)
++ def getAnonSuites(settings, version=None):
++ return CipherSuite._filterSuites(CipherSuite.anonSuites, settings, version)
+
+ dhAllSuites = dheCertSuites + anonSuites
+
+diff --git a/third_party/tlslite/tlslite/handshakesettings.py b/third_party/tlslite/tlslite/handshakesettings.py
+index 2e9e06d..2f11aaa 100644
+--- a/third_party/tlslite/tlslite/handshakesettings.py
++++ b/third_party/tlslite/tlslite/handshakesettings.py
+@@ -11,11 +11,9 @@ from .constants import CertificateType
+ from .utils import cryptomath
+ from .utils import cipherfactory
+
+-# RC4 is preferred as faster in Python, works in SSL3, and immune to CBC
+-# issues such as timing attacks
+-CIPHER_NAMES = ["rc4", "aes256", "aes128", "3des"]
+-MAC_NAMES = ["sha", "sha256"] # Don't allow "md5" by default.
+-ALL_MAC_NAMES = ["sha", "sha256", "md5"]
++CIPHER_NAMES = ["aes128gcm", "rc4", "aes256", "aes128", "3des"]
++MAC_NAMES = ["sha", "sha256", "aead"] # Don't allow "md5" by default.
++ALL_MAC_NAMES = MAC_NAMES + ["md5"]
+ KEY_EXCHANGE_NAMES = ["rsa", "dhe_rsa", "srp_sha", "srp_sha_rsa", "dh_anon"]
+ CIPHER_IMPLEMENTATIONS = ["openssl", "pycrypto", "python"]
+ CERTIFICATE_TYPES = ["x509"]
+@@ -42,7 +40,7 @@ class HandshakeSettings(object):
+ The default is 8193.
+
+ @type cipherNames: list
+- @ivar cipherNames: The allowed ciphers, in order of preference.
++ @ivar cipherNames: The allowed ciphers.
+
+ The allowed values in this list are 'aes256', 'aes128', '3des', and
+ 'rc4'. If these settings are used with a client handshake, they
+@@ -68,8 +66,7 @@ class HandshakeSettings(object):
+
+
+ @type certificateTypes: list
+- @ivar certificateTypes: The allowed certificate types, in order of
+- preference.
++ @ivar certificateTypes: The allowed certificate types.
+
+ The only allowed certificate type is 'x509'. This list is only used with a
+ client handshake. The client will advertise to the server which certificate
+@@ -197,10 +194,6 @@ class HandshakeSettings(object):
+ if not other.maxVersion in ((3,0), (3,1), (3,2), (3,3)):
+ raise ValueError("maxVersion set incorrectly")
+
+- if other.maxVersion < (3,3):
+- # No sha256 pre TLS 1.2
+- other.macNames = [e for e in self.macNames if e != "sha256"]
+-
+ return other
+
+ def _getCertificateTypes(self):
+diff --git a/third_party/tlslite/tlslite/tlsconnection.py b/third_party/tlslite/tlslite/tlsconnection.py
+index 3d97e97..0e13a78 100644
+--- a/third_party/tlslite/tlslite/tlsconnection.py
++++ b/third_party/tlslite/tlslite/tlsconnection.py
+@@ -1385,21 +1385,6 @@ class TLSConnection(TLSRecordLayer):
+
+ def _serverGetClientHello(self, settings, certChain, verifierDB,
+ sessionCache, anon, fallbackSCSV):
+- #Initialize acceptable cipher suites
+- cipherSuites = []
+- if verifierDB:
+- if certChain:
+- cipherSuites += \
+- CipherSuite.getSrpCertSuites(settings)
+- cipherSuites += CipherSuite.getSrpSuites(settings)
+- elif certChain:
+- cipherSuites += CipherSuite.getDheCertSuites(settings)
+- cipherSuites += CipherSuite.getCertSuites(settings)
+- elif anon:
+- cipherSuites += CipherSuite.getAnonSuites(settings)
+- else:
+- assert(False)
+-
+ #Tentatively set version to most-desirable version, so if an error
+ #occurs parsing the ClientHello, this is what we'll use for the
+ #error alert
+@@ -1451,7 +1436,22 @@ class TLSConnection(TLSRecordLayer):
+
+ else:
+ #Set the version to the client's version
+- self.version = clientHello.client_version
++ self.version = clientHello.client_version
++
++ #Initialize acceptable cipher suites
++ cipherSuites = []
++ if verifierDB:
++ if certChain:
++ cipherSuites += \
++ CipherSuite.getSrpCertSuites(settings, self.version)
++ cipherSuites += CipherSuite.getSrpSuites(settings, self.version)
++ elif certChain:
++ cipherSuites += CipherSuite.getDheCertSuites(settings, self.version)
++ cipherSuites += CipherSuite.getCertSuites(settings, self.version)
++ elif anon:
++ cipherSuites += CipherSuite.getAnonSuites(settings, self.version)
++ else:
++ assert(False)
+
+ #If resumption was requested and we have a session cache...
+ if clientHello.session_id and sessionCache:
+diff --git a/third_party/tlslite/tlslite/tlsrecordlayer.py b/third_party/tlslite/tlslite/tlsrecordlayer.py
+index a09499d..c3bcd8c 100644
+--- a/third_party/tlslite/tlslite/tlsrecordlayer.py
++++ b/third_party/tlslite/tlslite/tlsrecordlayer.py
+@@ -11,7 +11,8 @@ from __future__ import generators
+
+ from .utils.compat import *
+ from .utils.cryptomath import *
+-from .utils.cipherfactory import createAES, createRC4, createTripleDES
++from .utils.cipherfactory import createAESGCM, createAES, createRC4, \
++ createTripleDES
+ from .utils.codec import *
+ from .errors import *
+ from .messages import *
+@@ -592,10 +593,30 @@ class TLSRecordLayer(object):
+ if self.fault == Fault.badMAC:
+ macBytes[0] = (macBytes[0]+1) % 256
+
+- #Encrypt for Block or Stream Cipher
++ #Encrypt for non-NULL cipher.
+ if self._writeState.encContext:
++ #Seal (for AEAD)
++ if self._writeState.encContext.isAEAD:
++ #Assemble the authenticated data.
++ seqNumBytes = self._writeState.getSeqNumBytes()
++ authData = seqNumBytes + bytearray([contentType,
++ self.version[0],
++ self.version[1],
++ len(b)//256,
++ len(b)%256])
++
++ #The nonce is always the fixed nonce and the sequence number.
++ nonce = self._writeState.fixedNonce + seqNumBytes
++ assert len(nonce) == self._writeState.encContext.nonceLength
++
++ b = self._writeState.encContext.seal(nonce, b, authData)
++
++ #The only AEAD supported, AES-GCM, has an explicit variable
++ #nonce.
++ b = seqNumBytes + b
++
+ #Add padding and encrypt (for Block Cipher):
+- if self._writeState.encContext.isBlockCipher:
++ elif self._writeState.encContext.isBlockCipher:
+
+ #Add TLS 1.1 fixed block
+ if self.version >= (3,2):
+@@ -967,6 +988,43 @@ class TLSRecordLayer(object):
+
+ def _decryptRecord(self, recordType, b):
+ if self._readState.encContext:
++ #Open if it's an AEAD.
++ if self._readState.encContext.isAEAD:
++ #The only AEAD supported, AES-GCM, has an explicit variable
++ #nonce.
++ explicitNonceLength = 8
++ if explicitNonceLength > len(b):
++ #Publicly invalid.
++ for result in self._sendError(
++ AlertDescription.bad_record_mac,
++ "MAC failure (or padding failure)"):
++ yield result
++ nonce = self._readState.fixedNonce + b[:explicitNonceLength]
++ b = b[8:]
++
++ if self._readState.encContext.tagLength > len(b):
++ #Publicly invalid.
++ for result in self._sendError(
++ AlertDescription.bad_record_mac,
++ "MAC failure (or padding failure)"):
++ yield result
++
++ #Assemble the authenticated data.
++ seqnumBytes = self._readState.getSeqNumBytes()
++ plaintextLen = len(b) - self._readState.encContext.tagLength
++ authData = seqnumBytes + bytearray([recordType, self.version[0],
++ self.version[1],
++ plaintextLen//256,
++ plaintextLen%256])
++
++ b = self._readState.encContext.open(nonce, b, authData)
++ if b is None:
++ for result in self._sendError(
++ AlertDescription.bad_record_mac,
++ "MAC failure (or padding failure)"):
++ yield result
++ yield b
++ return
+
+ #Decrypt if it's a block cipher
+ if self._readState.encContext.isBlockCipher:
+@@ -1064,7 +1122,11 @@ class TLSRecordLayer(object):
+
+ def _calcPendingStates(self, cipherSuite, masterSecret,
+ clientRandom, serverRandom, implementations):
+- if cipherSuite in CipherSuite.aes128Suites:
++ if cipherSuite in CipherSuite.aes128GcmSuites:
++ keyLength = 16
++ ivLength = 4
++ createCipherFunc = createAESGCM
++ elif cipherSuite in CipherSuite.aes128Suites:
+ keyLength = 16
+ ivLength = 16
+ createCipherFunc = createAES
+@@ -1083,7 +1145,10 @@ class TLSRecordLayer(object):
+ else:
+ raise AssertionError()
+
+- if cipherSuite in CipherSuite.shaSuites:
++ if cipherSuite in CipherSuite.aeadSuites:
++ macLength = 0
++ digestmod = None
++ elif cipherSuite in CipherSuite.shaSuites:
+ macLength = 20
+ digestmod = hashlib.sha1
+ elif cipherSuite in CipherSuite.sha256Suites:
+@@ -1092,8 +1157,12 @@ class TLSRecordLayer(object):
+ elif cipherSuite in CipherSuite.md5Suites:
+ macLength = 16
+ digestmod = hashlib.md5
++ else:
++ raise AssertionError()
+
+- if self.version == (3,0):
++ if not digestmod:
++ createMACFunc = None
++ elif self.version == (3,0):
+ createMACFunc = createMAC_SSL
+ elif self.version in ((3,1), (3,2), (3,3)):
+ createMACFunc = createHMAC
+@@ -1128,16 +1197,28 @@ class TLSRecordLayer(object):
+ serverKeyBlock = p.getFixBytes(keyLength)
+ clientIVBlock = p.getFixBytes(ivLength)
+ serverIVBlock = p.getFixBytes(ivLength)
+- clientPendingState.macContext = createMACFunc(
+- compatHMAC(clientMACBlock), digestmod=digestmod)
+- serverPendingState.macContext = createMACFunc(
+- compatHMAC(serverMACBlock), digestmod=digestmod)
+- clientPendingState.encContext = createCipherFunc(clientKeyBlock,
+- clientIVBlock,
+- implementations)
+- serverPendingState.encContext = createCipherFunc(serverKeyBlock,
+- serverIVBlock,
+- implementations)
++ if digestmod:
++ # Legacy cipher.
++ clientPendingState.macContext = createMACFunc(
++ compatHMAC(clientMACBlock), digestmod=digestmod)
++ serverPendingState.macContext = createMACFunc(
++ compatHMAC(serverMACBlock), digestmod=digestmod)
++ clientPendingState.encContext = createCipherFunc(clientKeyBlock,
++ clientIVBlock,
++ implementations)
++ serverPendingState.encContext = createCipherFunc(serverKeyBlock,
++ serverIVBlock,
++ implementations)
++ else:
++ # AEAD.
++ clientPendingState.macContext = None
++ serverPendingState.macContext = None
++ clientPendingState.encContext = createCipherFunc(clientKeyBlock,
++ implementations)
++ serverPendingState.encContext = createCipherFunc(serverKeyBlock,
++ implementations)
++ clientPendingState.fixedNonce = clientIVBlock
++ serverPendingState.fixedNonce = serverIVBlock
+
+ #Assign new connection states to pending states
+ if self._client:
+diff --git a/third_party/tlslite/tlslite/utils/aes.py b/third_party/tlslite/tlslite/utils/aes.py
+index 95afaa3..5a038fb 100644
+--- a/third_party/tlslite/tlslite/utils/aes.py
++++ b/third_party/tlslite/tlslite/utils/aes.py
+@@ -12,6 +12,7 @@ class AES(object):
+ if len(IV) != 16:
+ raise AssertionError()
+ self.isBlockCipher = True
++ self.isAEAD = False
+ self.block_size = 16
+ self.implementation = implementation
+ if len(key)==16:
+@@ -31,4 +32,4 @@ class AES(object):
+ #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
++ assert(len(ciphertext) % 16 == 0)
+diff --git a/third_party/tlslite/tlslite/utils/aesgcm.py b/third_party/tlslite/tlslite/utils/aesgcm.py
+new file mode 100644
+index 0000000..7319c26
+--- /dev/null
++++ b/third_party/tlslite/tlslite/utils/aesgcm.py
+@@ -0,0 +1,193 @@
++# Author: Google
++# See the LICENSE file for legal information regarding use of this file.
++
++# GCM derived from Go's implementation in crypto/cipher.
++#
++# https://golang.org/src/crypto/cipher/gcm.go
++
++# GCM works over elements of the field GF(2^128), each of which is a 128-bit
++# polynomial. Throughout this implementation, polynomials are represented as
++# Python integers with the low-order terms at the most significant bits. So a
++# 128-bit polynomial is an integer from 0 to 2^128-1 with the most significant
++# bit representing the x^0 term and the least significant bit representing the
++# x^127 term. This bit reversal also applies to polynomials used as indices in a
++# look-up table.
++
++from .cryptomath import bytesToNumber, numberToByteArray
++
++class AESGCM(object):
++ """
++ AES-GCM implementation. Note: this implementation does not attempt
++ to be side-channel resistant. It's also rather slow.
++ """
++
++ def __init__(self, key, implementation, rawAesEncrypt):
++ self.isBlockCipher = False
++ self.isAEAD = True
++ self.nonceLength = 12
++ self.tagLength = 16
++ self.implementation = implementation
++ if len(key) == 16:
++ self.name = "aes128gcm"
++ elif len(key) == 32:
++ self.name = "aes256gcm"
++ else:
++ raise AssertionError()
++
++ self._rawAesEncrypt = rawAesEncrypt
++
++ # The GCM key is AES(0).
++ h = bytesToNumber(self._rawAesEncrypt(bytearray(16)))
++
++ # Pre-compute all 4-bit multiples of h. Note that bits are reversed
++ # because our polynomial representation places low-order terms at the
++ # most significant bit. Thus x^0 * h = h is at index 0b1000 = 8 and
++ # x^1 * h is at index 0b0100 = 4.
++ self._productTable = [0] * 16
++ self._productTable[_reverseBits(1)] = h
++ for i in range(2, 16, 2):
++ self._productTable[_reverseBits(i)] = \
++ _gcmShift(self._productTable[_reverseBits(i/2)])
++ self._productTable[_reverseBits(i+1)] = \
++ _gcmAdd(self._productTable[_reverseBits(i)], h)
++
++ def _rawAesCtrEncrypt(self, counter, inp):
++ """
++ Encrypts (or decrypts) plaintext with AES-CTR. counter is modified.
++ """
++ out = bytearray(len(inp))
++ for i in range(0, len(out), 16):
++ mask = self._rawAesEncrypt(counter)
++ for j in range(i, min(len(out), i + 16)):
++ out[j] = inp[j] ^ mask[j-i]
++ _inc32(counter)
++ return out
++
++ def _auth(self, ciphertext, ad, tagMask):
++ y = 0
++ y = self._update(y, ad)
++ y = self._update(y, ciphertext)
++ y ^= (len(ad) << (3 + 64)) | (len(ciphertext) << 3)
++ y = self._mul(y)
++ y ^= bytesToNumber(tagMask)
++ return numberToByteArray(y, 16)
++
++ def _update(self, y, data):
++ for i in range(0, len(data) // 16):
++ y ^= bytesToNumber(data[16*i:16*i+16])
++ y = self._mul(y)
++ extra = len(data) % 16
++ if extra != 0:
++ block = bytearray(16)
++ block[:extra] = data[-extra:]
++ y ^= bytesToNumber(block)
++ y = self._mul(y)
++ return y
++
++ def _mul(self, y):
++ """ Returns y*H, where H is the GCM key. """
++ ret = 0
++ # Multiply H by y 4 bits at a time, starting with the highest power
++ # terms.
++ for i in range(0, 128, 4):
++ # Multiply by x^4. The reduction for the top four terms is
++ # precomputed.
++ retHigh = ret & 0xf
++ ret >>= 4
++ ret ^= (_gcmReductionTable[retHigh] << (128-16))
++
++ # Add in y' * H where y' are the next four terms of y, shifted down
++ # to the x^0..x^4. This is one of the pre-computed multiples of
++ # H. The multiplication by x^4 shifts them back into place.
++ ret ^= self._productTable[y & 0xf]
++ y >>= 4
++ assert y == 0
++ return ret
++
++ def seal(self, nonce, plaintext, data):
++ """
++ Encrypts and authenticates plaintext using nonce and data. Returns the
++ ciphertext, consisting of the encrypted plaintext and tag concatenated.
++ """
++
++ if len(nonce) != 12:
++ raise ValueError("Bad nonce length")
++
++ # The initial counter value is the nonce, followed by a 32-bit counter
++ # that starts at 1. It's used to compute the tag mask.
++ counter = bytearray(16)
++ counter[:12] = nonce
++ counter[-1] = 1
++ tagMask = self._rawAesEncrypt(counter)
++
++ # The counter starts at 2 for the actual encryption.
++ counter[-1] = 2
++ ciphertext = self._rawAesCtrEncrypt(counter, plaintext)
++
++ tag = self._auth(ciphertext, data, tagMask)
++
++ return ciphertext + tag
++
++ def open(self, nonce, ciphertext, data):
++ """
++ Decrypts and authenticates ciphertext using nonce and data. If the
++ tag is valid, the plaintext is returned. If the tag is invalid,
++ returns None.
++ """
++
++ if len(nonce) != 12:
++ raise ValueError("Bad nonce length")
++ if len(ciphertext) < 16:
++ return None
++
++ tag = ciphertext[-16:]
++ ciphertext = ciphertext[:-16]
++
++ # The initial counter value is the nonce, followed by a 32-bit counter
++ # that starts at 1. It's used to compute the tag mask.
++ counter = bytearray(16)
++ counter[:12] = nonce
++ counter[-1] = 1
++ tagMask = self._rawAesEncrypt(counter)
++
++ if tag != self._auth(ciphertext, data, tagMask):
++ return None
++
++ # The counter starts at 2 for the actual decryption.
++ counter[-1] = 2
++ return self._rawAesCtrEncrypt(counter, ciphertext)
++
++def _reverseBits(i):
++ assert i < 16
++ i = ((i << 2) & 0xc) | ((i >> 2) & 0x3)
++ i = ((i << 1) & 0xa) | ((i >> 1) & 0x5)
++ return i
++
++def _gcmAdd(x, y):
++ return x ^ y
++
++def _gcmShift(x):
++ # Multiplying by x is a right shift, due to bit order.
++ highTermSet = x & 1
++ x >>= 1
++ if highTermSet:
++ # The x^127 term was shifted up to x^128, so subtract a 1+x+x^2+x^7
++ # term. This is 0b11100001 or 0xe1 when represented as an 8-bit
++ # polynomial.
++ x ^= 0xe1 << (128-8)
++ return x
++
++def _inc32(counter):
++ for i in range(len(counter)-1, len(counter)-5, -1):
++ counter[i] = (counter[i] + 1) % 256
++ if counter[i] != 0:
++ break
++ return counter
++
++# _gcmReductionTable[i] is i * (1+x+x^2+x^7) for all 4-bit polynomials i. The
++# result is stored as a 16-bit polynomial. This is used in the reduction step to
++# multiply elements of GF(2^128) by x^4.
++_gcmReductionTable = [
++ 0x0000, 0x1c20, 0x3840, 0x2460, 0x7080, 0x6ca0, 0x48c0, 0x54e0,
++ 0xe100, 0xfd20, 0xd940, 0xc560, 0x9180, 0x8da0, 0xa9c0, 0xb5e0,
++]
+diff --git a/third_party/tlslite/tlslite/utils/cipherfactory.py b/third_party/tlslite/tlslite/utils/cipherfactory.py
+index 20e20f1..d525644 100644
+--- a/third_party/tlslite/tlslite/utils/cipherfactory.py
++++ b/third_party/tlslite/tlslite/utils/cipherfactory.py
+@@ -6,6 +6,7 @@
+ import os
+
+ from tlslite.utils import python_aes
++from tlslite.utils import python_aesgcm
+ from tlslite.utils import python_rc4
+
+ from tlslite.utils import cryptomath
+@@ -20,6 +21,7 @@ if cryptomath.m2cryptoLoaded:
+
+ if cryptomath.pycryptoLoaded:
+ from tlslite.utils import pycrypto_aes
++ from tlslite.utils import pycrypto_aesgcm
+ from tlslite.utils import pycrypto_rc4
+ from tlslite.utils import pycrypto_tripledes
+ tripleDESPresent = True
+@@ -52,6 +54,25 @@ def createAES(key, IV, implList=None):
+ return python_aes.new(key, 2, IV)
+ raise NotImplementedError()
+
++def createAESGCM(key, implList=None):
++ """Create a new AESGCM object.
++
++ @type key: bytearray
++ @param key: A 16 or 32 byte byte array.
++
++ @rtype: L{tlslite.utils.AESGCM}
++ @return: An AESGCM object.
++ """
++ if implList == None:
++ implList = ["pycrypto", "python"]
++
++ for impl in implList:
++ if impl == "pycrypto" and cryptomath.pycryptoLoaded:
++ return pycrypto_aesgcm.new(key)
++ if impl == "python":
++ return python_aesgcm.new(key)
++ raise NotImplementedError()
++
+ def createRC4(key, IV, implList=None):
+ """Create a new RC4 object.
+
+@@ -99,4 +120,4 @@ def createTripleDES(key, IV, implList=None):
+ 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
++ raise NotImplementedError()
+diff --git a/third_party/tlslite/tlslite/utils/pycrypto_aesgcm.py b/third_party/tlslite/tlslite/utils/pycrypto_aesgcm.py
+new file mode 100644
+index 0000000..ee187ee
+--- /dev/null
++++ b/third_party/tlslite/tlslite/utils/pycrypto_aesgcm.py
+@@ -0,0 +1,16 @@
++# Author: Google
++# See the LICENSE file for legal information regarding use of this file.
++
++"""PyCrypto AES-GCM implementation."""
++
++from .cryptomath import *
++from .aesgcm import AESGCM
++
++if pycryptoLoaded:
++ import Crypto.Cipher.AES
++
++ def new(key):
++ cipher = Crypto.Cipher.AES.new(bytes(key))
++ def encrypt(plaintext):
++ return bytearray(cipher.encrypt(bytes(plaintext)))
++ return AESGCM(key, "pycrypto", encrypt)
+diff --git a/third_party/tlslite/tlslite/utils/python_aesgcm.py b/third_party/tlslite/tlslite/utils/python_aesgcm.py
+new file mode 100644
+index 0000000..80a5fd5
+--- /dev/null
++++ b/third_party/tlslite/tlslite/utils/python_aesgcm.py
+@@ -0,0 +1,10 @@
++# Author: Google
++# See the LICENSE file for legal information regarding use of this file.
++
++"""Pure-Python AES-GCM implementation."""
++
++from .aesgcm import AESGCM
++from .rijndael import rijndael
++
++def new(key):
++ return AESGCM(key, "python", rijndael(key, 16).encrypt)
+diff --git a/third_party/tlslite/tlslite/utils/rc4.py b/third_party/tlslite/tlslite/utils/rc4.py
+index 809026a..3853f5b 100644
+--- a/third_party/tlslite/tlslite/utils/rc4.py
++++ b/third_party/tlslite/tlslite/utils/rc4.py
+@@ -9,6 +9,7 @@ class RC4(object):
+ if len(keyBytes) < 16 or len(keyBytes) > 256:
+ raise ValueError()
+ self.isBlockCipher = False
++ self.isAEAD = False
+ self.name = "rc4"
+ self.implementation = implementation
+
+@@ -16,4 +17,4 @@ class RC4(object):
+ raise NotImplementedError()
+
+ def decrypt(self, ciphertext):
+- raise NotImplementedError()
+\ No newline at end of file
++ raise NotImplementedError()
+diff --git a/third_party/tlslite/tlslite/utils/tripledes.py b/third_party/tlslite/tlslite/utils/tripledes.py
+index 0b4d075..ddcdcad 100644
+--- a/third_party/tlslite/tlslite/utils/tripledes.py
++++ b/third_party/tlslite/tlslite/utils/tripledes.py
+@@ -12,6 +12,7 @@ class TripleDES(object):
+ if len(IV) != 8:
+ raise ValueError()
+ self.isBlockCipher = True
++ self.isAEAD = False
+ self.block_size = 8
+ self.implementation = implementation
+ self.name = "3des"
« no previous file with comments | « third_party/tlslite/README.chromium ('k') | third_party/tlslite/tests/tlstest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698