1 /** 2 * AES Key Wrap (RFC 3394) 3 * 4 * Copyright: 5 * (C) 2011 Jack Lloyd 6 * (C) 2014-2015 Etienne Cimon 7 * 8 * License: 9 * Botan is released under the Simplified BSD License (see LICENSE.md) 10 */ 11 module botan.constructs.rfc3394; 12 13 import botan.constants; 14 static if (BOTAN_HAS_RFC3394_KEYWRAP): 15 16 import botan.algo_base.symkey; 17 import botan.algo_factory.algo_factory; 18 import botan.block.block_cipher; 19 import botan.utils.loadstor; 20 import botan.utils.exceptn; 21 import botan.utils.xor_buf; 22 import botan.utils.mem_ops; 23 import botan.algo_factory.algo_factory; 24 import botan.utils.types; 25 26 /** 27 * Encrypt a key under a key encryption key using the algorithm 28 * described in RFC 3394 29 * 30 * Params: 31 * key = the plaintext key to encrypt 32 * kek = the key encryption key 33 * af = an algorithm factory 34 * Returns: key encrypted under kek 35 */ 36 SecureVector!ubyte rfc3394Keywrap()(auto const ref SecureVector!ubyte key, 37 in SymmetricKey kek, 38 AlgorithmFactory af) 39 { 40 if (key.length % 8 != 0) 41 throw new InvalidArgument("Bad input key size for NIST key wrap"); 42 43 Unique!BlockCipher aes = makeAes(kek.length, af); 44 aes.setKey(kek); 45 46 const size_t n = key.length / 8; 47 48 SecureVector!ubyte R = SecureVector!ubyte((n + 1) * 8); 49 SecureVector!ubyte A = SecureVector!ubyte(16); 50 51 foreach (size_t i; 0 .. 8) 52 A[i] = 0xA6; 53 54 copyMem(&R[8], key.ptr, key.length); 55 56 foreach (size_t j; 0 .. 5 + 1) 57 { 58 foreach (size_t i; 1 .. n + 1) 59 { 60 const uint t = cast(uint) ((n * j) + i); 61 62 copyMem(&A[8], &R[8*i], 8); 63 64 aes.encrypt(A.ptr); 65 copyMem(&R[8*i], &A[8], 8); 66 67 ubyte[4] t_buf; 68 storeBigEndian(t, t_buf.ptr); 69 xorBuf(&A[4], t_buf.ptr, 4); 70 } 71 } 72 73 copyMem(R.ptr, A.ptr, 8); 74 75 return R; 76 } 77 78 /** 79 * Decrypt a key under a key encryption key using the algorithm 80 * described in RFC 3394 81 * 82 * Params: 83 * key = the encrypted key to decrypt 84 * kek = the key encryption key 85 * af = an algorithm factory 86 * Returns: key decrypted under kek 87 */ 88 SecureVector!ubyte rfc3394Keyunwrap()(auto const ref SecureVector!ubyte key, 89 in SymmetricKey kek, 90 AlgorithmFactory af) 91 { 92 if (key.length < 16 || key.length % 8 != 0) 93 throw new InvalidArgument("Bad input key size for NIST key unwrap"); 94 95 Unique!BlockCipher aes = makeAes(kek.length, af); 96 aes.setKey(kek); 97 98 const size_t n = (key.length - 8) / 8; 99 100 SecureVector!ubyte R = SecureVector!ubyte(n * 8); 101 SecureVector!ubyte A = SecureVector!ubyte(16); 102 103 foreach (size_t i; 0 .. 8) 104 A[i] = key[i]; 105 106 copyMem(R.ptr, &key[8], key.length - 8); 107 108 foreach (size_t j; 0 .. 5 + 1) 109 { 110 for (size_t i = n; i != 0; --i) 111 { 112 const uint t = cast(uint)( (5 - j) * n + i ); 113 114 ubyte[4] t_buf; 115 storeBigEndian(t, &t_buf); 116 117 xorBuf(&A[4], t_buf.ptr, 4); 118 119 copyMem(&A[8], &R[8*(i-1)], 8); 120 121 aes.decrypt(A.ptr); 122 123 copyMem(&R[8*(i-1)], &A[8], 8); 124 } 125 } 126 127 if (loadBigEndian!ulong(A.ptr, 0) != 0xA6A6A6A6A6A6A6A6) 128 throw new IntegrityFailure("NIST key unwrap failed"); 129 130 return R; 131 } 132 133 private: 134 135 BlockCipher makeAes(size_t keylength, AlgorithmFactory af) 136 { 137 if (keylength == 16) 138 return af.makeBlockCipher("AES-128"); 139 else if (keylength == 24) 140 return af.makeBlockCipher("AES-192"); 141 else if (keylength == 32) 142 return af.makeBlockCipher("AES-256"); 143 else 144 throw new InvalidArgument("Bad KEK length for NIST keywrap"); 145 } 146 147 148 static if (BOTAN_TEST): 149 150 import botan.test; 151 import botan.codec.hex; 152 import botan.libstate.libstate; 153 154 size_t keywrapTest(string key_str, 155 string expected_str, 156 string kek_str) 157 { 158 size_t fail = 0; 159 160 try 161 { 162 SymmetricKey key = SymmetricKey(key_str); 163 SymmetricKey expected = SymmetricKey(expected_str); 164 SymmetricKey kek = SymmetricKey(kek_str); 165 166 AlgorithmFactory af = globalState().algorithmFactory(); 167 168 SecureVector!ubyte enc = rfc3394Keywrap(key.bitsOf(), kek, af); 169 170 if (enc != expected.bitsOf()) 171 { 172 logTrace("NIST key wrap encryption failure: ", hexEncode(enc), " != ", hexEncode(expected.bitsOf())); 173 fail++; 174 } 175 176 SecureVector!ubyte dec = rfc3394Keyunwrap(expected.bitsOf(), kek, af); 177 178 if (dec != key.bitsOf()) 179 { 180 logTrace("NIST key wrap decryption failure: " ~ hexEncode(dec) ~ " != " ~ hexEncode(key.bitsOf())); 181 fail++; 182 } 183 } 184 catch(Exception e) 185 { 186 logTrace(e.msg); 187 fail++; 188 } 189 190 return fail; 191 } 192 193 static if (BOTAN_HAS_TESTS && !SKIP_RFC3394_TEST) unittest 194 { 195 logDebug("Testing rfc3394.d ..."); 196 197 size_t fails = 0; 198 199 fails += keywrapTest("00112233445566778899AABBCCDDEEFF", 200 "1FA68B0A8112B447AEF34BD8FB5A7B829D3E862371D2CFE5", 201 "000102030405060708090A0B0C0D0E0F"); 202 203 fails += keywrapTest("00112233445566778899AABBCCDDEEFF", 204 "96778B25AE6CA435F92B5B97C050AED2468AB8A17AD84E5D", 205 "000102030405060708090A0B0C0D0E0F1011121314151617"); 206 207 fails += keywrapTest("00112233445566778899AABBCCDDEEFF", 208 "64E8C3F9CE0F5BA263E9777905818A2A93C8191E7D6E8AE7", 209 "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"); 210 211 fails += keywrapTest("00112233445566778899AABBCCDDEEFF0001020304050607", 212 "031D33264E15D33268F24EC260743EDCE1C6C7DDEE725A936BA814915C6762D2", 213 "000102030405060708090A0B0C0D0E0F1011121314151617"); 214 215 fails += keywrapTest("00112233445566778899AABBCCDDEEFF0001020304050607", 216 "A8F9BC1612C68B3FF6E6F4FBE30E71E4769C8B80A32CB8958CD5D17D6B254DA1", 217 "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"); 218 219 fails += keywrapTest("00112233445566778899AABBCCDDEEFF000102030405060708090A0B0C0D0E0F", 220 "28C9F404C4B810F4CBCCB35CFB87F8263F5786E2D80ED326CBC7F0E71A99F43BFB988B9B7A02DD21", 221 "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"); 222 223 testReport("rfc3394", 6, fails); 224 225 }