Package tlslite :: Package utils :: Module aesgcm
[hide private]
[frames] | no frames]

Source Code for Module tlslite.utils.aesgcm

  1  # Author: Google 
  2  # See the LICENSE file for legal information regarding use of this file. 
  3   
  4  # GCM derived from Go's implementation in crypto/cipher. 
  5  # 
  6  # https://golang.org/src/crypto/cipher/gcm.go 
  7   
  8  # GCM works over elements of the field GF(2^128), each of which is a 128-bit 
  9  # polynomial. Throughout this implementation, polynomials are represented as 
 10  # Python integers with the low-order terms at the most significant bits. So a 
 11  # 128-bit polynomial is an integer from 0 to 2^128-1 with the most significant 
 12  # bit representing the x^0 term and the least significant bit representing the 
 13  # x^127 term. This bit reversal also applies to polynomials used as indices in a 
 14  # look-up table. 
 15   
 16  from __future__ import division 
 17  from .cryptomath import bytesToNumber, numberToByteArray 
18 19 -class AESGCM(object):
20 """ 21 AES-GCM implementation. Note: this implementation does not attempt 22 to be side-channel resistant. It's also rather slow. 23 """ 24
25 - def __init__(self, key, implementation, rawAesEncrypt):
26 self.isBlockCipher = False 27 self.isAEAD = True 28 self.nonceLength = 12 29 self.tagLength = 16 30 self.implementation = implementation 31 if len(key) == 16: 32 self.name = "aes128gcm" 33 elif len(key) == 32: 34 self.name = "aes256gcm" 35 else: 36 raise AssertionError() 37 38 self._rawAesEncrypt = rawAesEncrypt 39 40 # The GCM key is AES(0). 41 h = bytesToNumber(self._rawAesEncrypt(bytearray(16))) 42 43 # Pre-compute all 4-bit multiples of h. Note that bits are reversed 44 # because our polynomial representation places low-order terms at the 45 # most significant bit. Thus x^0 * h = h is at index 0b1000 = 8 and 46 # x^1 * h is at index 0b0100 = 4. 47 self._productTable = [0] * 16 48 self._productTable[self._reverseBits(1)] = h 49 for i in range(2, 16, 2): 50 self._productTable[self._reverseBits(i)] = \ 51 self._gcmShift(self._productTable[self._reverseBits(i//2)]) 52 self._productTable[self._reverseBits(i+1)] = \ 53 self._gcmAdd(self._productTable[self._reverseBits(i)], h)
54
55 - def _rawAesCtrEncrypt(self, counter, inp):
56 """ 57 Encrypts (or decrypts) plaintext with AES-CTR. counter is modified. 58 """ 59 out = bytearray(len(inp)) 60 for i in range(0, len(out), 16): 61 mask = self._rawAesEncrypt(counter) 62 for j in range(i, min(len(out), i + 16)): 63 out[j] = inp[j] ^ mask[j-i] 64 self._inc32(counter) 65 return out
66
67 - def _auth(self, ciphertext, ad, tagMask):
68 y = 0 69 y = self._update(y, ad) 70 y = self._update(y, ciphertext) 71 y ^= (len(ad) << (3 + 64)) | (len(ciphertext) << 3) 72 y = self._mul(y) 73 y ^= bytesToNumber(tagMask) 74 return numberToByteArray(y, 16)
75
76 - def _update(self, y, data):
77 for i in range(0, len(data) // 16): 78 y ^= bytesToNumber(data[16*i:16*i+16]) 79 y = self._mul(y) 80 extra = len(data) % 16 81 if extra != 0: 82 block = bytearray(16) 83 block[:extra] = data[-extra:] 84 y ^= bytesToNumber(block) 85 y = self._mul(y) 86 return y
87
88 - def _mul(self, y):
89 """ Returns y*H, where H is the GCM key. """ 90 ret = 0 91 # Multiply H by y 4 bits at a time, starting with the highest power 92 # terms. 93 for i in range(0, 128, 4): 94 # Multiply by x^4. The reduction for the top four terms is 95 # precomputed. 96 retHigh = ret & 0xf 97 ret >>= 4 98 ret ^= (AESGCM._gcmReductionTable[retHigh] << (128-16)) 99 100 # Add in y' * H where y' are the next four terms of y, shifted down 101 # to the x^0..x^4. This is one of the pre-computed multiples of 102 # H. The multiplication by x^4 shifts them back into place. 103 ret ^= self._productTable[y & 0xf] 104 y >>= 4 105 assert y == 0 106 return ret
107
108 - def seal(self, nonce, plaintext, data):
109 """ 110 Encrypts and authenticates plaintext using nonce and data. Returns the 111 ciphertext, consisting of the encrypted plaintext and tag concatenated. 112 """ 113 114 if len(nonce) != 12: 115 raise ValueError("Bad nonce length") 116 117 # The initial counter value is the nonce, followed by a 32-bit counter 118 # that starts at 1. It's used to compute the tag mask. 119 counter = bytearray(16) 120 counter[:12] = nonce 121 counter[-1] = 1 122 tagMask = self._rawAesEncrypt(counter) 123 124 # The counter starts at 2 for the actual encryption. 125 counter[-1] = 2 126 ciphertext = self._rawAesCtrEncrypt(counter, plaintext) 127 128 tag = self._auth(ciphertext, data, tagMask) 129 130 return ciphertext + tag
131
132 - def open(self, nonce, ciphertext, data):
133 """ 134 Decrypts and authenticates ciphertext using nonce and data. If the 135 tag is valid, the plaintext is returned. If the tag is invalid, 136 returns None. 137 """ 138 139 if len(nonce) != 12: 140 raise ValueError("Bad nonce length") 141 if len(ciphertext) < 16: 142 return None 143 144 tag = ciphertext[-16:] 145 ciphertext = ciphertext[:-16] 146 147 # The initial counter value is the nonce, followed by a 32-bit counter 148 # that starts at 1. It's used to compute the tag mask. 149 counter = bytearray(16) 150 counter[:12] = nonce 151 counter[-1] = 1 152 tagMask = self._rawAesEncrypt(counter) 153 154 if tag != self._auth(ciphertext, data, tagMask): 155 return None 156 157 # The counter starts at 2 for the actual decryption. 158 counter[-1] = 2 159 return self._rawAesCtrEncrypt(counter, ciphertext)
160 161 @staticmethod
162 - def _reverseBits(i):
163 assert i < 16 164 i = ((i << 2) & 0xc) | ((i >> 2) & 0x3) 165 i = ((i << 1) & 0xa) | ((i >> 1) & 0x5) 166 return i
167 168 @staticmethod
169 - def _gcmAdd(x, y):
170 return x ^ y
171 172 @staticmethod
173 - def _gcmShift(x):
174 # Multiplying by x is a right shift, due to bit order. 175 highTermSet = x & 1 176 x >>= 1 177 if highTermSet: 178 # The x^127 term was shifted up to x^128, so subtract a 1+x+x^2+x^7 179 # term. This is 0b11100001 or 0xe1 when represented as an 8-bit 180 # polynomial. 181 x ^= 0xe1 << (128-8) 182 return x
183 184 @staticmethod
185 - def _inc32(counter):
186 for i in range(len(counter)-1, len(counter)-5, -1): 187 counter[i] = (counter[i] + 1) % 256 188 if counter[i] != 0: 189 break 190 return counter
191 192 # _gcmReductionTable[i] is i * (1+x+x^2+x^7) for all 4-bit polynomials i. The 193 # result is stored as a 16-bit polynomial. This is used in the reduction step to 194 # multiply elements of GF(2^128) by x^4. 195 _gcmReductionTable = [ 196 0x0000, 0x1c20, 0x3840, 0x2460, 0x7080, 0x6ca0, 0x48c0, 0x54e0, 197 0xe100, 0xfd20, 0xd940, 0xc560, 0x9180, 0x8da0, 0xa9c0, 0xb5e0, 198 ]
199