| 21 | | |
|---|
| 22 | | from Python_AES import Python_AES |
|---|
| | 21 | import random |
|---|
| | 22 | import array |
|---|
| | 23 | import math |
|---|
| | 24 | |
|---|
| | 25 | """cryptomath module |
|---|
| | 26 | |
|---|
| | 27 | This module has basic math/crypto code.""" |
|---|
| | 28 | |
|---|
| | 29 | import os |
|---|
| | 30 | import math |
|---|
| | 31 | import base64 |
|---|
| | 32 | import binascii |
|---|
| | 33 | import sha |
|---|
| | 34 | |
|---|
| | 35 | #from compat import * |
|---|
| | 36 | |
|---|
| | 37 | |
|---|
| | 38 | # ************************************************************************** |
|---|
| | 39 | # Load Optional Modules |
|---|
| | 40 | # ************************************************************************** |
|---|
| | 41 | |
|---|
| | 42 | # Try to load M2Crypto/OpenSSL |
|---|
| | 43 | try: |
|---|
| | 44 | from M2Crypto import m2 |
|---|
| | 45 | m2cryptoLoaded = 1 |
|---|
| | 46 | |
|---|
| | 47 | except ImportError: |
|---|
| | 48 | m2cryptoLoaded = 0 |
|---|
| | 49 | |
|---|
| | 50 | |
|---|
| | 51 | # Try to load cryptlib |
|---|
| | 52 | try: |
|---|
| | 53 | import cryptlib_py |
|---|
| | 54 | try: |
|---|
| | 55 | cryptlib_py.cryptInit() |
|---|
| | 56 | except cryptlib_py.CryptException, e: |
|---|
| | 57 | #If tlslite and cryptoIDlib are both present, |
|---|
| | 58 | #they might each try to re-initialize this, |
|---|
| | 59 | #so we're tolerant of that. |
|---|
| | 60 | if e[0] != cryptlib_py.CRYPT_ERROR_INITED: |
|---|
| | 61 | raise |
|---|
| | 62 | cryptlibpyLoaded = 1 |
|---|
| | 63 | |
|---|
| | 64 | except ImportError: |
|---|
| | 65 | cryptlibpyLoaded = 0 |
|---|
| | 66 | |
|---|
| | 67 | #Try to load GMPY |
|---|
| | 68 | try: |
|---|
| | 69 | import gmpy |
|---|
| | 70 | gmpyLoaded = 1 |
|---|
| | 71 | except ImportError: |
|---|
| | 72 | gmpyLoaded = 0 |
|---|
| | 73 | |
|---|
| | 74 | #Try to load pycrypto |
|---|
| | 75 | try: |
|---|
| | 76 | import Crypto.Cipher.AES |
|---|
| | 77 | pycryptoLoaded = 1 |
|---|
| | 78 | except ImportError: |
|---|
| | 79 | pycryptoLoaded = 0 |
|---|
| | 80 | |
|---|
| | 81 | |
|---|
| | 82 | # ************************************************************************** |
|---|
| | 83 | # PRNG Functions |
|---|
| | 84 | # ************************************************************************** |
|---|
| | 85 | |
|---|
| | 86 | # Get os.urandom PRNG |
|---|
| | 87 | try: |
|---|
| | 88 | os.urandom(1) |
|---|
| | 89 | def getRandomBytes(howMany): |
|---|
| | 90 | return stringToBytes(os.urandom(howMany)) |
|---|
| | 91 | prngName = "os.urandom" |
|---|
| | 92 | |
|---|
| | 93 | except: |
|---|
| | 94 | # Else get cryptlib PRNG |
|---|
| | 95 | if cryptlibpyLoaded: |
|---|
| | 96 | def getRandomBytes(howMany): |
|---|
| | 97 | randomKey = cryptlib_py.cryptCreateContext(cryptlib_py.CRYPT_UNUSED, |
|---|
| | 98 | cryptlib_py.CRYPT_ALGO_AES) |
|---|
| | 99 | cryptlib_py.cryptSetAttribute(randomKey, |
|---|
| | 100 | cryptlib_py.CRYPT_CTXINFO_MODE, |
|---|
| | 101 | cryptlib_py.CRYPT_MODE_OFB) |
|---|
| | 102 | cryptlib_py.cryptGenerateKey(randomKey) |
|---|
| | 103 | bytes = createByteArrayZeros(howMany) |
|---|
| | 104 | cryptlib_py.cryptEncrypt(randomKey, bytes) |
|---|
| | 105 | return bytes |
|---|
| | 106 | prngName = "cryptlib" |
|---|
| | 107 | |
|---|
| | 108 | else: |
|---|
| | 109 | #Else get UNIX /dev/urandom PRNG |
|---|
| | 110 | try: |
|---|
| | 111 | devRandomFile = open("/dev/urandom", "rb") |
|---|
| | 112 | def getRandomBytes(howMany): |
|---|
| | 113 | return stringToBytes(devRandomFile.read(howMany)) |
|---|
| | 114 | prngName = "/dev/urandom" |
|---|
| | 115 | except IOError: |
|---|
| | 116 | #Else get Win32 CryptoAPI PRNG |
|---|
| | 117 | try: |
|---|
| | 118 | import win32prng |
|---|
| | 119 | def getRandomBytes(howMany): |
|---|
| | 120 | s = win32prng.getRandomBytes(howMany) |
|---|
| | 121 | if len(s) != howMany: |
|---|
| | 122 | raise AssertionError() |
|---|
| | 123 | return stringToBytes(s) |
|---|
| | 124 | prngName ="CryptoAPI" |
|---|
| | 125 | except ImportError: |
|---|
| | 126 | #Else no PRNG :-( |
|---|
| | 127 | def getRandomBytes(howMany): |
|---|
| | 128 | raise NotImplementedError("No Random Number Generator "\ |
|---|
| | 129 | "available.") |
|---|
| | 130 | prngName = "None" |
|---|
| | 131 | |
|---|
| | 132 | # ************************************************************************** |
|---|
| | 133 | # Converter Functions |
|---|
| | 134 | # ************************************************************************** |
|---|
| | 135 | |
|---|
| | 136 | def bytesToNumber(bytes): |
|---|
| | 137 | total = 0L |
|---|
| | 138 | multiplier = 1L |
|---|
| | 139 | for count in range(len(bytes)-1, -1, -1): |
|---|
| | 140 | byte = bytes[count] |
|---|
| | 141 | total += multiplier * byte |
|---|
| | 142 | multiplier *= 256 |
|---|
| | 143 | return total |
|---|
| | 144 | |
|---|
| | 145 | def numberToBytes(n): |
|---|
| | 146 | howManyBytes = numBytes(n) |
|---|
| | 147 | bytes = createByteArrayZeros(howManyBytes) |
|---|
| | 148 | for count in range(howManyBytes-1, -1, -1): |
|---|
| | 149 | bytes[count] = int(n % 256) |
|---|
| | 150 | n >>= 8 |
|---|
| | 151 | return bytes |
|---|
| | 152 | |
|---|
| | 153 | def bytesToBase64(bytes): |
|---|
| | 154 | s = bytesToString(bytes) |
|---|
| | 155 | return stringToBase64(s) |
|---|
| | 156 | |
|---|
| | 157 | def base64ToBytes(s): |
|---|
| | 158 | s = base64ToString(s) |
|---|
| | 159 | return stringToBytes(s) |
|---|
| | 160 | |
|---|
| | 161 | def numberToBase64(n): |
|---|
| | 162 | bytes = numberToBytes(n) |
|---|
| | 163 | return bytesToBase64(bytes) |
|---|
| | 164 | |
|---|
| | 165 | def base64ToNumber(s): |
|---|
| | 166 | bytes = base64ToBytes(s) |
|---|
| | 167 | return bytesToNumber(bytes) |
|---|
| | 168 | |
|---|
| | 169 | def stringToNumber(s): |
|---|
| | 170 | bytes = stringToBytes(s) |
|---|
| | 171 | return bytesToNumber(bytes) |
|---|
| | 172 | |
|---|
| | 173 | def numberToString(s): |
|---|
| | 174 | bytes = numberToBytes(s) |
|---|
| | 175 | return bytesToString(bytes) |
|---|
| | 176 | |
|---|
| | 177 | def base64ToString(s): |
|---|
| | 178 | try: |
|---|
| | 179 | return base64.decodestring(s) |
|---|
| | 180 | except binascii.Error, e: |
|---|
| | 181 | raise SyntaxError(e) |
|---|
| | 182 | except binascii.Incomplete, e: |
|---|
| | 183 | raise SyntaxError(e) |
|---|
| | 184 | |
|---|
| | 185 | def stringToBase64(s): |
|---|
| | 186 | return base64.encodestring(s).replace("\n", "") |
|---|
| | 187 | |
|---|
| | 188 | def mpiToNumber(mpi): #mpi is an openssl-format bignum string |
|---|
| | 189 | if (ord(mpi[4]) & 0x80) !=0: #Make sure this is a positive number |
|---|
| | 190 | raise AssertionError() |
|---|
| | 191 | bytes = stringToBytes(mpi[4:]) |
|---|
| | 192 | return bytesToNumber(bytes) |
|---|
| | 193 | |
|---|
| | 194 | def numberToMPI(n): |
|---|
| | 195 | bytes = numberToBytes(n) |
|---|
| | 196 | ext = 0 |
|---|
| | 197 | #If the high-order bit is going to be set, |
|---|
| | 198 | #add an extra byte of zeros |
|---|
| | 199 | if (numBits(n) & 0x7)==0: |
|---|
| | 200 | ext = 1 |
|---|
| | 201 | length = numBytes(n) + ext |
|---|
| | 202 | bytes = concatArrays(createByteArrayZeros(4+ext), bytes) |
|---|
| | 203 | bytes[0] = (length >> 24) & 0xFF |
|---|
| | 204 | bytes[1] = (length >> 16) & 0xFF |
|---|
| | 205 | bytes[2] = (length >> 8) & 0xFF |
|---|
| | 206 | bytes[3] = length & 0xFF |
|---|
| | 207 | return bytesToString(bytes) |
|---|
| | 208 | |
|---|
| | 209 | |
|---|
| | 210 | |
|---|
| | 211 | # ************************************************************************** |
|---|
| | 212 | # Misc. Utility Functions |
|---|
| | 213 | # ************************************************************************** |
|---|
| | 214 | |
|---|
| | 215 | def numBytes(n): |
|---|
| | 216 | if n==0: |
|---|
| | 217 | return 0 |
|---|
| | 218 | bits = numBits(n) |
|---|
| | 219 | return int(math.ceil(bits / 8.0)) |
|---|
| | 220 | |
|---|
| | 221 | def hashAndBase64(s): |
|---|
| | 222 | return stringToBase64(sha.sha(s).digest()) |
|---|
| | 223 | |
|---|
| | 224 | def getBase64Nonce(numChars=22): #defaults to an 132 bit nonce |
|---|
| | 225 | bytes = getRandomBytes(numChars) |
|---|
| | 226 | bytesStr = "".join([chr(b) for b in bytes]) |
|---|
| | 227 | return stringToBase64(bytesStr)[:numChars] |
|---|
| | 228 | |
|---|
| | 229 | |
|---|
| | 230 | # ************************************************************************** |
|---|
| | 231 | # Big Number Math |
|---|
| | 232 | # ************************************************************************** |
|---|
| | 233 | |
|---|
| | 234 | def getRandomNumber(low, high): |
|---|
| | 235 | if low >= high: |
|---|
| | 236 | raise AssertionError() |
|---|
| | 237 | howManyBits = numBits(high) |
|---|
| | 238 | howManyBytes = numBytes(high) |
|---|
| | 239 | lastBits = howManyBits % 8 |
|---|
| | 240 | while 1: |
|---|
| | 241 | bytes = getRandomBytes(howManyBytes) |
|---|
| | 242 | if lastBits: |
|---|
| | 243 | bytes[0] = bytes[0] % (1 << lastBits) |
|---|
| | 244 | n = bytesToNumber(bytes) |
|---|
| | 245 | if n >= low and n < high: |
|---|
| | 246 | return n |
|---|
| | 247 | |
|---|
| | 248 | def gcd(a,b): |
|---|
| | 249 | a, b = max(a,b), min(a,b) |
|---|
| | 250 | while b: |
|---|
| | 251 | a, b = b, a % b |
|---|
| | 252 | return a |
|---|
| | 253 | |
|---|
| | 254 | def lcm(a, b): |
|---|
| | 255 | #This will break when python division changes, but we can't use // cause |
|---|
| | 256 | #of Jython |
|---|
| | 257 | return (a * b) / gcd(a, b) |
|---|
| | 258 | |
|---|
| | 259 | #Returns inverse of a mod b, zero if none |
|---|
| | 260 | #Uses Extended Euclidean Algorithm |
|---|
| | 261 | def invMod(a, b): |
|---|
| | 262 | c, d = a, b |
|---|
| | 263 | uc, ud = 1, 0 |
|---|
| | 264 | while c != 0: |
|---|
| | 265 | #This will break when python division changes, but we can't use // |
|---|
| | 266 | #cause of Jython |
|---|
| | 267 | q = d / c |
|---|
| | 268 | c, d = d-(q*c), c |
|---|
| | 269 | uc, ud = ud - (q * uc), uc |
|---|
| | 270 | if d == 1: |
|---|
| | 271 | return ud % b |
|---|
| | 272 | return 0 |
|---|
| | 273 | |
|---|
| | 274 | |
|---|
| | 275 | if gmpyLoaded: |
|---|
| | 276 | def powMod(base, power, modulus): |
|---|
| | 277 | base = gmpy.mpz(base) |
|---|
| | 278 | power = gmpy.mpz(power) |
|---|
| | 279 | modulus = gmpy.mpz(modulus) |
|---|
| | 280 | result = pow(base, power, modulus) |
|---|
| | 281 | return long(result) |
|---|
| | 282 | |
|---|
| | 283 | else: |
|---|
| | 284 | #Copied from Bryan G. Olson's post to comp.lang.python |
|---|
| | 285 | #Does left-to-right instead of pow()'s right-to-left, |
|---|
| | 286 | #thus about 30% faster than the python built-in with small bases |
|---|
| | 287 | def powMod(base, power, modulus): |
|---|
| | 288 | nBitScan = 5 |
|---|
| | 289 | |
|---|
| | 290 | """ Return base**power mod modulus, using multi bit scanning |
|---|
| | 291 | with nBitScan bits at a time.""" |
|---|
| | 292 | |
|---|
| | 293 | #TREV - Added support for negative exponents |
|---|
| | 294 | negativeResult = 0 |
|---|
| | 295 | if (power < 0): |
|---|
| | 296 | power *= -1 |
|---|
| | 297 | negativeResult = 1 |
|---|
| | 298 | |
|---|
| | 299 | exp2 = 2**nBitScan |
|---|
| | 300 | mask = exp2 - 1 |
|---|
| | 301 | |
|---|
| | 302 | # Break power into a list of digits of nBitScan bits. |
|---|
| | 303 | # The list is recursive so easy to read in reverse direction. |
|---|
| | 304 | nibbles = None |
|---|
| | 305 | while power: |
|---|
| | 306 | nibbles = int(power & mask), nibbles |
|---|
| | 307 | power = power >> nBitScan |
|---|
| | 308 | |
|---|
| | 309 | # Make a table of powers of base up to 2**nBitScan - 1 |
|---|
| | 310 | lowPowers = [1] |
|---|
| | 311 | for i in xrange(1, exp2): |
|---|
| | 312 | lowPowers.append((lowPowers[i-1] * base) % modulus) |
|---|
| | 313 | |
|---|
| | 314 | # To exponentiate by the first nibble, look it up in the table |
|---|
| | 315 | nib, nibbles = nibbles |
|---|
| | 316 | prod = lowPowers[nib] |
|---|
| | 317 | |
|---|
| | 318 | # For the rest, square nBitScan times, then multiply by |
|---|
| | 319 | # base^nibble |
|---|
| | 320 | while nibbles: |
|---|
| | 321 | nib, nibbles = nibbles |
|---|
| | 322 | for i in xrange(nBitScan): |
|---|
| | 323 | prod = (prod * prod) % modulus |
|---|
| | 324 | if nib: prod = (prod * lowPowers[nib]) % modulus |
|---|
| | 325 | |
|---|
| | 326 | #TREV - Added support for negative exponents |
|---|
| | 327 | if negativeResult: |
|---|
| | 328 | prodInv = invMod(prod, modulus) |
|---|
| | 329 | #Check to make sure the inverse is correct |
|---|
| | 330 | if (prod * prodInv) % modulus != 1: |
|---|
| | 331 | raise AssertionError() |
|---|
| | 332 | return prodInv |
|---|
| | 333 | return prod |
|---|
| | 334 | |
|---|
| | 335 | |
|---|
| | 336 | #Pre-calculate a sieve of the ~100 primes < 1000: |
|---|
| | 337 | def makeSieve(n): |
|---|
| | 338 | sieve = range(n) |
|---|
| | 339 | for count in range(2, int(math.sqrt(n))): |
|---|
| | 340 | if sieve[count] == 0: |
|---|
| | 341 | continue |
|---|
| | 342 | x = sieve[count] * 2 |
|---|
| | 343 | while x < len(sieve): |
|---|
| | 344 | sieve[x] = 0 |
|---|
| | 345 | x += sieve[count] |
|---|
| | 346 | sieve = [x for x in sieve[2:] if x] |
|---|
| | 347 | return sieve |
|---|
| | 348 | |
|---|
| | 349 | sieve = makeSieve(1000) |
|---|
| | 350 | |
|---|
| | 351 | def isPrime(n, iterations=5, display=0): |
|---|
| | 352 | #Trial division with sieve |
|---|
| | 353 | for x in sieve: |
|---|
| | 354 | if x >= n: return 1 |
|---|
| | 355 | if n % x == 0: return 0 |
|---|
| | 356 | #Passed trial division, proceed to Rabin-Miller |
|---|
| | 357 | #Rabin-Miller implemented per Ferguson & Schneier |
|---|
| | 358 | #Compute s, t for Rabin-Miller |
|---|
| | 359 | if display: print "*", |
|---|
| | 360 | s, t = n-1, 0 |
|---|
| | 361 | while s % 2 == 0: |
|---|
| | 362 | s, t = s/2, t+1 |
|---|
| | 363 | #Repeat Rabin-Miller x times |
|---|
| | 364 | a = 2 #Use 2 as a base for first iteration speedup, per HAC |
|---|
| | 365 | for count in range(iterations): |
|---|
| | 366 | v = powMod(a, s, n) |
|---|
| | 367 | if v==1: |
|---|
| | 368 | continue |
|---|
| | 369 | i = 0 |
|---|
| | 370 | while v != n-1: |
|---|
| | 371 | if i == t-1: |
|---|
| | 372 | return 0 |
|---|
| | 373 | else: |
|---|
| | 374 | v, i = powMod(v, 2, n), i+1 |
|---|
| | 375 | a = getRandomNumber(2, n) |
|---|
| | 376 | return 1 |
|---|
| | 377 | |
|---|
| | 378 | def getRandomPrime(bits, display=0): |
|---|
| | 379 | if bits < 10: |
|---|
| | 380 | raise AssertionError() |
|---|
| | 381 | #The 1.5 ensures the 2 MSBs are set |
|---|
| | 382 | #Thus, when used for p,q in RSA, n will have its MSB set |
|---|
| | 383 | # |
|---|
| | 384 | #Since 30 is lcm(2,3,5), we'll set our test numbers to |
|---|
| | 385 | #29 % 30 and keep them there |
|---|
| | 386 | low = (2L ** (bits-1)) * 3/2 |
|---|
| | 387 | high = 2L ** bits - 30 |
|---|
| | 388 | p = getRandomNumber(low, high) |
|---|
| | 389 | p += 29 - (p % 30) |
|---|
| | 390 | while 1: |
|---|
| | 391 | if display: print ".", |
|---|
| | 392 | p += 30 |
|---|
| | 393 | if p >= high: |
|---|
| | 394 | p = getRandomNumber(low, high) |
|---|
| | 395 | p += 29 - (p % 30) |
|---|
| | 396 | if isPrime(p, display=display): |
|---|
| | 397 | return p |
|---|
| | 398 | |
|---|
| | 399 | #Unused at the moment... |
|---|
| | 400 | def getRandomSafePrime(bits, display=0): |
|---|
| | 401 | if bits < 10: |
|---|
| | 402 | raise AssertionError() |
|---|
| | 403 | #The 1.5 ensures the 2 MSBs are set |
|---|
| | 404 | #Thus, when used for p,q in RSA, n will have its MSB set |
|---|
| | 405 | # |
|---|
| | 406 | #Since 30 is lcm(2,3,5), we'll set our test numbers to |
|---|
| | 407 | #29 % 30 and keep them there |
|---|
| | 408 | low = (2 ** (bits-2)) * 3/2 |
|---|
| | 409 | high = (2 ** (bits-1)) - 30 |
|---|
| | 410 | q = getRandomNumber(low, high) |
|---|
| | 411 | q += 29 - (q % 30) |
|---|
| | 412 | while 1: |
|---|
| | 413 | if display: print ".", |
|---|
| | 414 | q += 30 |
|---|
| | 415 | if (q >= high): |
|---|
| | 416 | q = getRandomNumber(low, high) |
|---|
| | 417 | q += 29 - (q % 30) |
|---|
| | 418 | #Ideas from Tom Wu's SRP code |
|---|
| | 419 | #Do trial division on p and q before Rabin-Miller |
|---|
| | 420 | if isPrime(q, 0, display=display): |
|---|
| | 421 | p = (2 * q) + 1 |
|---|
| | 422 | if isPrime(p, display=display): |
|---|
| | 423 | if isPrime(q, display=display): |
|---|
| | 424 | return p |
|---|
| | 425 | |
|---|
| | 426 | |
|---|
| | 427 | class AES: |
|---|
| | 428 | def __init__(self, key, mode, IV, implementation): |
|---|
| | 429 | if len(key) not in (16, 24, 32): |
|---|
| | 430 | raise AssertionError() |
|---|
| | 431 | if mode != 2: |
|---|
| | 432 | raise AssertionError() |
|---|
| | 433 | if len(IV) != 16: |
|---|
| | 434 | raise AssertionError() |
|---|
| | 435 | self.isBlockCipher = 1 # True |
|---|
| | 436 | self.block_size = 16 |
|---|
| | 437 | self.implementation = implementation |
|---|
| | 438 | if len(key)==16: |
|---|
| | 439 | self.name = "aes128" |
|---|
| | 440 | elif len(key)==24: |
|---|
| | 441 | self.name = "aes192" |
|---|
| | 442 | elif len(key)==32: |
|---|
| | 443 | self.name = "aes256" |
|---|
| | 444 | else: |
|---|
| | 445 | raise AssertionError() |
|---|
| | 446 | |
|---|
| | 447 | #CBC-Mode encryption, returns ciphertext |
|---|
| | 448 | #WARNING: *MAY* modify the input as well |
|---|
| | 449 | def encrypt(self, plaintext): |
|---|
| | 450 | assert(len(plaintext) % 16 == 0) |
|---|
| | 451 | |
|---|
| | 452 | #CBC-Mode decryption, returns plaintext |
|---|
| | 453 | #WARNING: *MAY* modify the input as well |
|---|
| | 454 | def decrypt(self, ciphertext): |
|---|
| | 455 | assert(len(ciphertext) % 16 == 0) |
|---|
| | 456 | |
|---|
| | 457 | """ |
|---|
| | 458 | A pure python (slow) implementation of rijndael with a decent interface |
|---|
| | 459 | |
|---|
| | 460 | To include - |
|---|
| | 461 | |
|---|
| | 462 | from rijndael import rijndael |
|---|
| | 463 | |
|---|
| | 464 | To do a key setup - |
|---|
| | 465 | |
|---|
| | 466 | r = rijndael(key, block_size = 16) |
|---|
| | 467 | |
|---|
| | 468 | key must be a string of length 16, 24, or 32 |
|---|
| | 469 | blocksize must be 16, 24, or 32. Default is 16 |
|---|
| | 470 | |
|---|
| | 471 | To use - |
|---|
| | 472 | |
|---|
| | 473 | ciphertext = r.encrypt(plaintext) |
|---|
| | 474 | plaintext = r.decrypt(ciphertext) |
|---|
| | 475 | |
|---|
| | 476 | If any strings are of the wrong length a ValueError is thrown |
|---|
| | 477 | """ |
|---|
| | 478 | |
|---|
| | 479 | # ported from the Java reference code by Bram Cohen, bram@gawth.com, April 2001 |
|---|
| | 480 | # this code is public domain, unless someone makes |
|---|
| | 481 | # an intellectual property claim against the reference |
|---|
| | 482 | # code, in which case it can be made public domain by |
|---|
| | 483 | # deleting all the comments and renaming all the variables |
|---|
| | 484 | |
|---|
| | 485 | import copy |
|---|
| | 486 | import string |
|---|
| | 487 | |
|---|
| | 488 | |
|---|
| | 489 | |
|---|
| | 490 | #----------------------- |
|---|
| | 491 | #TREV - ADDED BECAUSE THERE'S WARNINGS ABOUT INT OVERFLOW BEHAVIOR CHANGING IN |
|---|
| | 492 | #2.4..... |
|---|
| | 493 | import os |
|---|
| | 494 | if os.name != "java": |
|---|
| | 495 | import exceptions |
|---|
| | 496 | if hasattr(exceptions, "FutureWarning"): |
|---|
| | 497 | import warnings |
|---|
| | 498 | warnings.filterwarnings("ignore", category=FutureWarning, append=1) |
|---|
| | 499 | #----------------------- |
|---|
| | 500 | |
|---|
| | 501 | |
|---|
| | 502 | |
|---|
| | 503 | shifts = [[[0, 0], [1, 3], [2, 2], [3, 1]], |
|---|
| | 504 | [[0, 0], [1, 5], [2, 4], [3, 3]], |
|---|
| | 505 | [[0, 0], [1, 7], [3, 5], [4, 4]]] |
|---|
| | 506 | |
|---|
| | 507 | # [keysize][block_size] |
|---|
| | 508 | num_rounds = {16: {16: 10, 24: 12, 32: 14}, 24: {16: 12, 24: 12, 32: 14}, 32: {16: 14, 24: 14, 32: 14}} |
|---|
| | 509 | |
|---|
| | 510 | A = [[1, 1, 1, 1, 1, 0, 0, 0], |
|---|
| | 511 | [0, 1, 1, 1, 1, 1, 0, 0], |
|---|
| | 512 | [0, 0, 1, 1, 1, 1, 1, 0], |
|---|
| | 513 | [0, 0, 0, 1, 1, 1, 1, 1], |
|---|
| | 514 | [1, 0, 0, 0, 1, 1, 1, 1], |
|---|
| | 515 | [1, 1, 0, 0, 0, 1, 1, 1], |
|---|
| | 516 | [1, 1, 1, 0, 0, 0, 1, 1], |
|---|
| | 517 | [1, 1, 1, 1, 0, 0, 0, 1]] |
|---|
| | 518 | |
|---|
| | 519 | # produce log and alog tables, needed for multiplying in the |
|---|
| | 520 | # field GF(2^m) (generator = 3) |
|---|
| | 521 | alog = [1] |
|---|
| | 522 | for i in xrange(255): |
|---|
| | 523 | j = (alog[-1] << 1) ^ alog[-1] |
|---|
| | 524 | if j & 0x100 != 0: |
|---|
| | 525 | j ^= 0x11B |
|---|
| | 526 | alog.append(j) |
|---|
| | 527 | |
|---|
| | 528 | log = [0] * 256 |
|---|
| | 529 | for i in xrange(1, 255): |
|---|
| | 530 | log[alog[i]] = i |
|---|
| | 531 | |
|---|
| | 532 | # multiply two elements of GF(2^m) |
|---|
| | 533 | def mul(a, b): |
|---|
| | 534 | if a == 0 or b == 0: |
|---|
| | 535 | return 0 |
|---|
| | 536 | return alog[(log[a & 0xFF] + log[b & 0xFF]) % 255] |
|---|
| | 537 | |
|---|
| | 538 | # substitution box based on F^{-1}(x) |
|---|
| | 539 | box = [[0] * 8 for i in xrange(256)] |
|---|
| | 540 | box[1][7] = 1 |
|---|
| | 541 | for i in xrange(2, 256): |
|---|
| | 542 | j = alog[255 - log[i]] |
|---|
| | 543 | for t in xrange(8): |
|---|
| | 544 | box[i][t] = (j >> (7 - t)) & 0x01 |
|---|
| | 545 | |
|---|
| | 546 | B = [0, 1, 1, 0, 0, 0, 1, 1] |
|---|
| | 547 | |
|---|
| | 548 | # affine transform: box[i] <- B + A*box[i] |
|---|
| | 549 | cox = [[0] * 8 for i in xrange(256)] |
|---|
| | 550 | for i in xrange(256): |
|---|
| | 551 | for t in xrange(8): |
|---|
| | 552 | cox[i][t] = B[t] |
|---|
| | 553 | for j in xrange(8): |
|---|
| | 554 | cox[i][t] ^= A[t][j] * box[i][j] |
|---|
| | 555 | |
|---|
| | 556 | # S-boxes and inverse S-boxes |
|---|
| | 557 | S = [0] * 256 |
|---|
| | 558 | Si = [0] * 256 |
|---|
| | 559 | for i in xrange(256): |
|---|
| | 560 | S[i] = cox[i][0] << 7 |
|---|
| | 561 | for t in xrange(1, 8): |
|---|
| | 562 | S[i] ^= cox[i][t] << (7-t) |
|---|
| | 563 | Si[S[i] & 0xFF] = i |
|---|
| | 564 | |
|---|
| | 565 | # T-boxes |
|---|
| | 566 | G = [[2, 1, 1, 3], |
|---|
| | 567 | [3, 2, 1, 1], |
|---|
| | 568 | [1, 3, 2, 1], |
|---|
| | 569 | [1, 1, 3, 2]] |
|---|
| | 570 | |
|---|
| | 571 | AA = [[0] * 8 for i in xrange(4)] |
|---|
| | 572 | |
|---|
| | 573 | for i in xrange(4): |
|---|
| | 574 | for j in xrange(4): |
|---|
| | 575 | AA[i][j] = G[i][j] |
|---|
| | 576 | AA[i][i+4] = 1 |
|---|
| | 577 | |
|---|
| | 578 | for i in xrange(4): |
|---|
| | 579 | pivot = AA[i][i] |
|---|
| | 580 | if pivot == 0: |
|---|
| | 581 | t = i + 1 |
|---|
| | 582 | while AA[t][i] == 0 and t < 4: |
|---|
| | 583 | t += 1 |
|---|
| | 584 | assert t != 4, 'G matrix must be invertible' |
|---|
| | 585 | for j in xrange(8): |
|---|
| | 586 | AA[i][j], AA[t][j] = AA[t][j], AA[i][j] |
|---|
| | 587 | pivot = AA[i][i] |
|---|
| | 588 | for j in xrange(8): |
|---|
| | 589 | if AA[i][j] != 0: |
|---|
| | 590 | AA[i][j] = alog[(255 + log[AA[i][j] & 0xFF] - log[pivot & 0xFF]) % 255] |
|---|
| | 591 | for t in xrange(4): |
|---|
| | 592 | if i != t: |
|---|
| | 593 | for j in xrange(i+1, 8): |
|---|
| | 594 | AA[t][j] ^= mul(AA[i][j], AA[t][i]) |
|---|
| | 595 | AA[t][i] = 0 |
|---|
| | 596 | |
|---|
| | 597 | iG = [[0] * 4 for i in xrange(4)] |
|---|
| | 598 | |
|---|
| | 599 | for i in xrange(4): |
|---|
| | 600 | for j in xrange(4): |
|---|
| | 601 | iG[i][j] = AA[i][j + 4] |
|---|
| | 602 | |
|---|
| | 603 | def mul4(a, bs): |
|---|
| | 604 | if a == 0: |
|---|
| | 605 | return 0 |
|---|
| | 606 | r = 0 |
|---|
| | 607 | for b in bs: |
|---|
| | 608 | r <<= 8 |
|---|
| | 609 | if b != 0: |
|---|
| | 610 | r = r | mul(a, b) |
|---|
| | 611 | return r |
|---|
| | 612 | |
|---|
| | 613 | T1 = [] |
|---|
| | 614 | T2 = [] |
|---|
| | 615 | T3 = [] |
|---|
| | 616 | T4 = [] |
|---|
| | 617 | T5 = [] |
|---|
| | 618 | T6 = [] |
|---|
| | 619 | T7 = [] |
|---|
| | 620 | T8 = [] |
|---|
| | 621 | U1 = [] |
|---|
| | 622 | U2 = [] |
|---|
| | 623 | U3 = [] |
|---|
| | 624 | U4 = [] |
|---|
| | 625 | |
|---|
| | 626 | for t in xrange(256): |
|---|
| | 627 | s = S[t] |
|---|
| | 628 | T1.append(mul4(s, G[0])) |
|---|
| | 629 | T2.append(mul4(s, G[1])) |
|---|
| | 630 | T3.append(mul4(s, G[2])) |
|---|
| | 631 | T4.append(mul4(s, G[3])) |
|---|
| | 632 | |
|---|
| | 633 | s = Si[t] |
|---|
| | 634 | T5.append(mul4(s, iG[0])) |
|---|
| | 635 | T6.append(mul4(s, iG[1])) |
|---|
| | 636 | T7.append(mul4(s, iG[2])) |
|---|
| | 637 | T8.append(mul4(s, iG[3])) |
|---|
| | 638 | |
|---|
| | 639 | U1.append(mul4(t, iG[0])) |
|---|
| | 640 | U2.append(mul4(t, iG[1])) |
|---|
| | 641 | U3.append(mul4(t, iG[2])) |
|---|
| | 642 | U4.append(mul4(t, iG[3])) |
|---|
| | 643 | |
|---|
| | 644 | # round constants |
|---|
| | 645 | rcon = [1] |
|---|
| | 646 | r = 1 |
|---|
| | 647 | for t in xrange(1, 30): |
|---|
| | 648 | r = mul(2, r) |
|---|
| | 649 | rcon.append(r) |
|---|
| | 650 | |
|---|
| | 651 | del A |
|---|
| | 652 | del AA |
|---|
| | 653 | del pivot |
|---|
| | 654 | del B |
|---|
| | 655 | del G |
|---|
| | 656 | del box |
|---|
| | 657 | del log |
|---|
| | 658 | del alog |
|---|
| | 659 | del i |
|---|
| | 660 | del j |
|---|
| | 661 | del r |
|---|
| | 662 | del s |
|---|
| | 663 | del t |
|---|
| | 664 | del mul |
|---|
| | 665 | del mul4 |
|---|
| | 666 | del cox |
|---|
| | 667 | del iG |
|---|
| | 668 | |
|---|
| | 669 | class rijndael: |
|---|
| | 670 | def __init__(self, key, block_size = 16): |
|---|
| | 671 | if block_size != 16 and block_size != 24 and block_size != 32: |
|---|
| | 672 | raise ValueError('Invalid block size: ' + str(block_size)) |
|---|
| | 673 | if len(key) != 16 and len(key) != 24 and len(key) != 32: |
|---|
| | 674 | raise ValueError('Invalid key size: ' + str(len(key))) |
|---|
| | 675 | self.block_size = block_size |
|---|
| | 676 | |
|---|
| | 677 | ROUNDS = num_rounds[len(key)][block_size] |
|---|
| | 678 | BC = block_size / 4 |
|---|
| | 679 | # encryption round keys |
|---|
| | 680 | Ke = [[0] * BC for i in xrange(ROUNDS + 1)] |
|---|
| | 681 | # decryption round keys |
|---|
| | 682 | Kd = [[0] * BC for i in xrange(ROUNDS + 1)] |
|---|
| | 683 | ROUND_KEY_COUNT = (ROUNDS + 1) * BC |
|---|
| | 684 | KC = len(key) / 4 |
|---|
| | 685 | |
|---|
| | 686 | # copy user material bytes into temporary ints |
|---|
| | 687 | tk = [] |
|---|
| | 688 | for i in xrange(0, KC): |
|---|
| | 689 | tk.append((ord(key[i * 4]) << 24) | (ord(key[i * 4 + 1]) << 16) | |
|---|
| | 690 | (ord(key[i * 4 + 2]) << 8) | ord(key[i * 4 + 3])) |
|---|
| | 691 | |
|---|
| | 692 | # copy values into round key arrays |
|---|
| | 693 | t = 0 |
|---|
| | 694 | j = 0 |
|---|
| | 695 | while j < KC and t < ROUND_KEY_COUNT: |
|---|
| | 696 | Ke[t / BC][t % BC] = tk[j] |
|---|
| | 697 | Kd[ROUNDS - (t / BC)][t % BC] = tk[j] |
|---|
| | 698 | j += 1 |
|---|
| | 699 | t += 1 |
|---|
| | 700 | tt = 0 |
|---|
| | 701 | rconpointer = 0 |
|---|
| | 702 | while t < ROUND_KEY_COUNT: |
|---|
| | 703 | # extrapolate using phi (the round key evolution function) |
|---|
| | 704 | tt = tk[KC - 1] |
|---|
| | 705 | tk[0] ^= (S[(tt >> 16) & 0xFF] & 0xFF) << 24 ^ \ |
|---|
| | 706 | (S[(tt >> 8) & 0xFF] & 0xFF) << 16 ^ \ |
|---|
| | 707 | (S[ tt & 0xFF] & 0xFF) << 8 ^ \ |
|---|
| | 708 | (S[(tt >> 24) & 0xFF] & 0xFF) ^ \ |
|---|
| | 709 | (rcon[rconpointer] & 0xFF) << 24 |
|---|
| | 710 | rconpointer += 1 |
|---|
| | 711 | if KC != 8: |
|---|
| | 712 | for i in xrange(1, KC): |
|---|
| | 713 | tk[i] ^= tk[i-1] |
|---|
| | 714 | else: |
|---|
| | 715 | for i in xrange(1, KC / 2): |
|---|
| | 716 | tk[i] ^= tk[i-1] |
|---|
| | 717 | tt = tk[KC / 2 - 1] |
|---|
| | 718 | tk[KC / 2] ^= (S[ tt & 0xFF] & 0xFF) ^ \ |
|---|
| | 719 | (S[(tt >> 8) & 0xFF] & 0xFF) << 8 ^ \ |
|---|
| | 720 | (S[(tt >> 16) & 0xFF] & 0xFF) << 16 ^ \ |
|---|
| | 721 | (S[(tt >> 24) & 0xFF] & 0xFF) << 24 |
|---|
| | 722 | for i in xrange(KC / 2 + 1, KC): |
|---|
| | 723 | tk[i] ^= tk[i-1] |
|---|
| | 724 | # copy values into round key arrays |
|---|
| | 725 | j = 0 |
|---|
| | 726 | while j < KC and t < ROUND_KEY_COUNT: |
|---|
| | 727 | Ke[t / BC][t % BC] = tk[j] |
|---|
| | 728 | Kd[ROUNDS - (t / BC)][t % BC] = tk[j] |
|---|
| | 729 | j += 1 |
|---|
| | 730 | t += 1 |
|---|
| | 731 | # inverse MixColumn where needed |
|---|
| | 732 | for r in xrange(1, ROUNDS): |
|---|
| | 733 | for j in xrange(BC): |
|---|
| | 734 | tt = Kd[r][j] |
|---|
| | 735 | Kd[r][j] = U1[(tt >> 24) & 0xFF] ^ \ |
|---|
| | 736 | U2[(tt >> 16) & 0xFF] ^ \ |
|---|
| | 737 | U3[(tt >> 8) & 0xFF] ^ \ |
|---|
| | 738 | U4[ tt & 0xFF] |
|---|
| | 739 | self.Ke = Ke |
|---|
| | 740 | self.Kd = Kd |
|---|
| | 741 | |
|---|
| | 742 | def encrypt(self, plaintext): |
|---|
| | 743 | if len(plaintext) != self.block_size: |
|---|
| | 744 | raise ValueError('wrong block length, expected ' + str(self.block_size) + ' got ' + str(len(plaintext))) |
|---|
| | 745 | Ke = self.Ke |
|---|
| | 746 | |
|---|
| | 747 | BC = self.block_size / 4 |
|---|
| | 748 | ROUNDS = len(Ke) - 1 |
|---|
| | 749 | if BC == 4: |
|---|
| | 750 | SC = 0 |
|---|
| | 751 | elif BC == 6: |
|---|
| | 752 | SC = 1 |
|---|
| | 753 | else: |
|---|
| | 754 | SC = 2 |
|---|
| | 755 | s1 = shifts[SC][1][0] |
|---|
| | 756 | s2 = shifts[SC][2][0] |
|---|
| | 757 | s3 = shifts[SC][3][0] |
|---|
| | 758 | a = [0] * BC |
|---|
| | 759 | # temporary work array |
|---|
| | 760 | t = [] |
|---|
| | 761 | # plaintext to ints + key |
|---|
| | 762 | for i in xrange(BC): |
|---|
| | 763 | t.append((ord(plaintext[i * 4 ]) << 24 | |
|---|
| | 764 | ord(plaintext[i * 4 + 1]) << 16 | |
|---|
| | 765 | ord(plaintext[i * 4 + 2]) << 8 | |
|---|
| | 766 | ord(plaintext[i * 4 + 3]) ) ^ Ke[0][i]) |
|---|
| | 767 | # apply round transforms |
|---|
| | 768 | for r in xrange(1, ROUNDS): |
|---|
| | 769 | for i in xrange(BC): |
|---|
| | 770 | a[i] = (T1[(t[ i ] >> 24) & 0xFF] ^ |
|---|
| | 771 | T2[(t[(i + s1) % BC] >> 16) & 0xFF] ^ |
|---|
| | 772 | T3[(t[(i + s2) % BC] >> 8) & 0xFF] ^ |
|---|
| | 773 | T4[ t[(i + s3) % BC] & 0xFF] ) ^ Ke[r][i] |
|---|
| | 774 | t = copy.copy(a) |
|---|
| | 775 | # last round is special |
|---|
| | 776 | result = [] |
|---|
| | 777 | for i in xrange(BC): |
|---|
| | 778 | tt = Ke[ROUNDS][i] |
|---|
| | 779 | result.append((S[(t[ i ] >> 24) & 0xFF] ^ (tt >> 24)) & 0xFF) |
|---|
| | 780 | result.append((S[(t[(i + s1) % BC] >> 16) & 0xFF] ^ (tt >> 16)) & 0xFF) |
|---|
| | 781 | result.append((S[(t[(i + s2) % BC] >> 8) & 0xFF] ^ (tt >> 8)) & 0xFF) |
|---|
| | 782 | result.append((S[ t[(i + s3) % BC] & 0xFF] ^ tt ) & 0xFF) |
|---|
| | 783 | return string.join(map(chr, result), '') |
|---|
| | 784 | |
|---|
| | 785 | def decrypt(self, ciphertext): |
|---|
| | 786 | if len(ciphertext) != self.block_size: |
|---|
| | 787 | raise ValueError('wrong block length, expected ' + str(self.block_size) + ' got ' + str(len(plaintext))) |
|---|
| | 788 | Kd = self.Kd |
|---|
| | 789 | |
|---|
| | 790 | BC = self.block_size / 4 |
|---|
| | 791 | ROUNDS = len(Kd) - 1 |
|---|
| | 792 | if BC == 4: |
|---|
| | 793 | SC = 0 |
|---|
| | 794 | elif BC == 6: |
|---|
| | 795 | SC = 1 |
|---|
| | 796 | else: |
|---|
| | 797 | SC = 2 |
|---|
| | 798 | s1 = shifts[SC][1][1] |
|---|
| | 799 | s2 = shifts[SC][2][1] |
|---|
| | 800 | s3 = shifts[SC][3][1] |
|---|
| | 801 | a = [0] * BC |
|---|
| | 802 | # temporary work array |
|---|
| | 803 | t = [0] * BC |
|---|
| | 804 | # ciphertext to ints + key |
|---|
| | 805 | for i in xrange(BC): |
|---|
| | 806 | t[i] = (ord(ciphertext[i * 4 ]) << 24 | |
|---|
| | 807 | ord(ciphertext[i * 4 + 1]) << 16 | |
|---|
| | 808 | ord(ciphertext[i * 4 + 2]) << 8 | |
|---|
| | 809 | ord(ciphertext[i * 4 + 3]) ) ^ Kd[0][i] |
|---|
| | 810 | # apply round transforms |
|---|
| | 811 | for r in xrange(1, ROUNDS): |
|---|
| | 812 | for i in xrange(BC): |
|---|
| | 813 | a[i] = (T5[(t[ i ] >> 24) & 0xFF] ^ |
|---|
| | 814 | T6[(t[(i + s1) % BC] >> 16) & 0xFF] ^ |
|---|
| | 815 | T7[(t[(i + s2) % BC] >> 8) & 0xFF] ^ |
|---|
| | 816 | T8[ t[(i + s3) % BC] & 0xFF] ) ^ Kd[r][i] |
|---|
| | 817 | t = copy.copy(a) |
|---|
| | 818 | # last round is special |
|---|
| | 819 | result = [] |
|---|
| | 820 | for i in xrange(BC): |
|---|
| | 821 | tt = Kd[ROUNDS][i] |
|---|
| | 822 | result.append((Si[(t[ i ] >> 24) & 0xFF] ^ (tt >> 24)) & 0xFF) |
|---|
| | 823 | result.append((Si[(t[(i + s1) % BC] >> 16) & 0xFF] ^ (tt >> 16)) & 0xFF) |
|---|
| | 824 | result.append((Si[(t[(i + s2) % BC] >> 8) & 0xFF] ^ (tt >> 8)) & 0xFF) |
|---|
| | 825 | result.append((Si[ t[(i + s3) % BC] & 0xFF] ^ tt ) & 0xFF) |
|---|
| | 826 | return string.join(map(chr, result), '') |
|---|
| | 827 | |
|---|
| | 828 | def encrypt(key, block): |
|---|
| | 829 | return rijndael(key, len(block)).encrypt(block) |
|---|
| | 830 | |
|---|
| | 831 | def decrypt(key, block): |
|---|
| | 832 | return rijndael(key, len(block)).decrypt(block) |
|---|
| | 833 | |
|---|
| | 834 | def test(): |
|---|
| | 835 | def t(kl, bl): |
|---|
| | 836 | b = 'b' * bl |
|---|
| | 837 | r = rijndael('a' * kl, bl) |
|---|
| | 838 | assert r.decrypt(r.encrypt(b)) == b |
|---|
| | 839 | t(16, 16) |
|---|
| | 840 | t(16, 24) |
|---|
| | 841 | t(16, 32) |
|---|
| | 842 | t(24, 16) |
|---|
| | 843 | t(24, 24) |
|---|
| | 844 | t(24, 32) |
|---|
| | 845 | t(32, 16) |
|---|
| | 846 | t(32, 24) |
|---|
| | 847 | t(32, 32) |
|---|
| | 848 | |
|---|
| | 849 | |
|---|
| | 850 | |
|---|
| | 851 | def createByteArraySequence(seq): |
|---|
| | 852 | return array.array('B', seq) |
|---|
| | 853 | |
|---|
| | 854 | def createByteArrayZeros(howMany): |
|---|
| | 855 | return array.array('B', [0] * howMany) |
|---|
| | 856 | |
|---|
| | 857 | def concatArrays(a1, a2): |
|---|
| | 858 | return a1+a2 |
|---|
| | 859 | |
|---|
| | 860 | def bytesToString(bytes): |
|---|
| | 861 | return bytes.tostring() |
|---|
| | 862 | |
|---|
| | 863 | def stringToBytes(s): |
|---|
| | 864 | bytes = createByteArrayZeros(0) |
|---|
| | 865 | bytes.fromstring(s) |
|---|
| | 866 | return bytes |
|---|
| | 867 | |
|---|
| | 868 | def new(key, mode, IV): |
|---|
| | 869 | return Python_AES(key, mode, IV) |
|---|
| | 870 | |
|---|
| | 871 | class Python_AES(AES): |
|---|
| | 872 | def __init__(self, key, mode, IV): |
|---|
| | 873 | AES.__init__(self, key, mode, IV, "python") |
|---|
| | 874 | self.rijndael = rijndael(key, 16) |
|---|
| | 875 | self.IV = IV |
|---|
| | 876 | |
|---|
| | 877 | def encrypt(self, plaintext): |
|---|
| | 878 | AES.encrypt(self, plaintext) |
|---|
| | 879 | |
|---|
| | 880 | plaintextBytes = stringToBytes(plaintext) |
|---|
| | 881 | chainBytes = stringToBytes(self.IV) |
|---|
| | 882 | |
|---|
| | 883 | #CBC Mode: For each block... |
|---|
| | 884 | for x in range(len(plaintextBytes)/16): |
|---|
| | 885 | |
|---|
| | 886 | #XOR with the chaining block |
|---|
| | 887 | blockBytes = plaintextBytes[x*16 : (x*16)+16] |
|---|
| | 888 | for y in range(16): |
|---|
| | 889 | blockBytes[y] ^= chainBytes[y] |
|---|
| | 890 | blockString = bytesToString(blockBytes) |
|---|
| | 891 | |
|---|
| | 892 | #Encrypt it |
|---|
| | 893 | encryptedBytes = stringToBytes(self.rijndael.encrypt(blockString)) |
|---|
| | 894 | |
|---|
| | 895 | #Overwrite the input with the output |
|---|
| | 896 | for y in range(16): |
|---|
| | 897 | plaintextBytes[(x*16)+y] = encryptedBytes[y] |
|---|
| | 898 | |
|---|
| | 899 | #Set the next chaining block |
|---|
| | 900 | chainBytes = encryptedBytes |
|---|
| | 901 | |
|---|
| | 902 | self.IV = bytesToString(chainBytes) |
|---|
| | 903 | return bytesToString(plaintextBytes) |
|---|
| | 904 | |
|---|
| | 905 | def decrypt(self, ciphertext): |
|---|
| | 906 | AES.decrypt(self, ciphertext) |
|---|
| | 907 | |
|---|
| | 908 | ciphertextBytes = stringToBytes(ciphertext) |
|---|
| | 909 | chainBytes = stringToBytes(self.IV) |
|---|
| | 910 | |
|---|
| | 911 | #CBC Mode: For each block... |
|---|
| | 912 | for x in range(len(ciphertextBytes)/16): |
|---|
| | 913 | |
|---|
| | 914 | #Decrypt it |
|---|
| | 915 | blockBytes = ciphertextBytes[x*16 : (x*16)+16] |
|---|
| | 916 | blockString = bytesToString(blockBytes) |
|---|
| | 917 | decryptedBytes = stringToBytes(self.rijndael.decrypt(blockString)) |
|---|
| | 918 | |
|---|
| | 919 | #XOR with the chaining block and overwrite the input with output |
|---|
| | 920 | for y in range(16): |
|---|
| | 921 | decryptedBytes[y] ^= chainBytes[y] |
|---|
| | 922 | ciphertextBytes[(x*16)+y] = decryptedBytes[y] |
|---|
| | 923 | |
|---|
| | 924 | #Set the next chaining block |
|---|
| | 925 | chainBytes = blockBytes |
|---|
| | 926 | |
|---|
| | 927 | self.IV = bytesToString(chainBytes) |
|---|
| | 928 | return bytesToString(ciphertextBytes) |
|---|