]>
Raphaƫl G. Git Repositories - youtubedl/blob - youtube_dl/aes.py
   1 __all__ 
= ['aes_encrypt', 'key_expansion', 'aes_ctr_decrypt', 'aes_decrypt_text'] 
   6 from .utils 
import bytes_to_intlist
, intlist_to_bytes
 
  10 def aes_ctr_decrypt(data
, key
, counter
): 
  12     Decrypt with aes in counter mode 
  14     @param {int[]} data        cipher 
  15     @param {int[]} key         16/24/32-Byte cipher key 
  16     @param {instance} counter  Instance whose next_value function (@returns {int[]}  16-Byte block) 
  17                                returns the next counter block 
  18     @returns {int[]}           decrypted data 
  20     expanded_key 
= key_expansion(key
) 
  21     block_count 
= int(ceil(float(len(data
)) / BLOCK_SIZE_BYTES
)) 
  24     for i 
in range(block_count
): 
  25         counter_block 
= counter
.next_value() 
  26         block 
= data
[i
*BLOCK_SIZE_BYTES 
: (i
+1)*BLOCK_SIZE_BYTES
] 
  27         block 
+= [0]*(BLOCK_SIZE_BYTES 
- len(block
)) 
  29         cipher_counter_block 
= aes_encrypt(counter_block
, expanded_key
) 
  30         decrypted_data 
+= xor(block
, cipher_counter_block
) 
  31     decrypted_data 
= decrypted_data
[:len(data
)] 
  35 def key_expansion(data
): 
  39     @param {int[]} data  16/24/32-Byte cipher key 
  40     @returns {int[]}     176/208/240-Byte expanded key  
  44     key_size_bytes 
= len(data
) 
  45     expanded_key_size_bytes 
= (key_size_bytes 
// 4 + 7) * BLOCK_SIZE_BYTES
 
  47     while len(data
) < expanded_key_size_bytes
: 
  49         temp 
= key_schedule_core(temp
, rcon_iteration
) 
  51         data 
+= xor(temp
, data
[-key_size_bytes 
: 4-key_size_bytes
]) 
  55             data 
+= xor(temp
, data
[-key_size_bytes 
: 4-key_size_bytes
]) 
  57         if key_size_bytes 
== 32: 
  59             temp 
= sub_bytes(temp
) 
  60             data 
+= xor(temp
, data
[-key_size_bytes 
: 4-key_size_bytes
]) 
  62         for _ 
in range(3 if key_size_bytes 
== 32  else 2 if key_size_bytes 
== 24 else 0): 
  64             data 
+= xor(temp
, data
[-key_size_bytes 
: 4-key_size_bytes
]) 
  65     data 
= data
[:expanded_key_size_bytes
] 
  69 def aes_encrypt(data
, expanded_key
): 
  71     Encrypt one block with aes 
  73     @param {int[]} data          16-Byte state 
  74     @param {int[]} expanded_key  176/208/240-Byte expanded key  
  75     @returns {int[]}             16-Byte cipher 
  77     rounds 
= len(expanded_key
) // BLOCK_SIZE_BYTES 
- 1 
  79     data 
= xor(data
, expanded_key
[:BLOCK_SIZE_BYTES
]) 
  80     for i 
in range(1, rounds
+1): 
  81         data 
= sub_bytes(data
) 
  82         data 
= shift_rows(data
) 
  84             data 
= mix_columns(data
) 
  85         data 
= xor(data
, expanded_key
[i
*BLOCK_SIZE_BYTES 
: (i
+1)*BLOCK_SIZE_BYTES
]) 
  89 def aes_decrypt_text(data
, password
, key_size_bytes
): 
  92     - The first 8 Bytes of decoded 'data' are the 8 high Bytes of the counter 
  93     - The cipher key is retrieved by encrypting the first 16 Byte of 'password' 
  94       with the first 'key_size_bytes' Bytes from 'password' (if necessary filled with 0's) 
  95     - Mode of operation is 'counter' 
  97     @param {str} data                    Base64 encoded string 
  98     @param {str,unicode} password        Password (will be encoded with utf-8) 
  99     @param {int} key_size_bytes          Possible values: 16 for 128-Bit, 24 for 192-Bit or 32 for 256-Bit 
 100     @returns {str}                       Decrypted data 
 102     NONCE_LENGTH_BYTES 
= 8 
 104     data 
= bytes_to_intlist(base64
.b64decode(data
)) 
 105     password 
= bytes_to_intlist(password
.encode('utf-8')) 
 107     key 
= password
[:key_size_bytes
] + [0]*(key_size_bytes 
- len(password
)) 
 108     key 
= aes_encrypt(key
[:BLOCK_SIZE_BYTES
], key_expansion(key
)) * (key_size_bytes 
// BLOCK_SIZE_BYTES
) 
 110     nonce 
= data
[:NONCE_LENGTH_BYTES
] 
 111     cipher 
= data
[NONCE_LENGTH_BYTES
:] 
 114         __value 
= nonce 
+ [0]*(BLOCK_SIZE_BYTES 
- NONCE_LENGTH_BYTES
) 
 115         def next_value(self
): 
 117             self
.__value 
= inc(self
.__value
) 
 120     decrypted_data 
= aes_ctr_decrypt(cipher
, key
, Counter()) 
 121     plaintext 
= intlist_to_bytes(decrypted_data
) 
 125 RCON 
= (0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36) 
 126 SBOX 
= (0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, 
 127         0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 
 128         0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, 
 129         0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, 
 130         0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 
 131         0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, 
 132         0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, 
 133         0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 
 134         0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, 
 135         0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, 
 136         0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 
 137         0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, 
 138         0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, 
 139         0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 
 140         0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, 
 141         0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16) 
 142 MIX_COLUMN_MATRIX 
= ((2,3,1,1), 
 148     return [SBOX
[x
] for x 
in data
] 
 151     return data
[1:] + [data
[0]] 
 153 def key_schedule_core(data
, rcon_iteration
): 
 155     data 
= sub_bytes(data
) 
 156     data
[0] = data
[0] ^ RCON
[rcon_iteration
] 
 160 def xor(data1
, data2
): 
 161     return [x^y 
for x
, y 
in zip(data1
, data2
)] 
 163 def mix_column(data
): 
 167         for column 
in range(4): 
 168             addend 
= data
[column
] 
 169             if MIX_COLUMN_MATRIX
[row
][column
] in (2,3): 
 174                 if MIX_COLUMN_MATRIX
[row
][column
] == 3: 
 175                     addend ^
= data
[column
] 
 176             mixed ^
= addend 
& 0xff 
 177         data_mixed
.append(mixed
) 
 180 def mix_columns(data
): 
 183         column 
= data
[i
*4 : (i
+1)*4] 
 184         data_mixed 
+= mix_column(column
) 
 187 def shift_rows(data
): 
 189     for column 
in range(4): 
 191             data_shifted
.append( data
[((column 
+ row
) & 0b11) * 4 + row
] ) 
 195     data 
= data
[:] # copy 
 196     for i 
in range(len(data
)-1,-1,-1): 
 200             data
[i
] = data
[i
] + 1