1 /* 2 * Copyright 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <keymaster/km_openssl/ckdf.h> 18 19 #include <assert.h> 20 21 #include <openssl/aes.h> 22 #include <openssl/cmac.h> 23 24 #include <keymaster/km_openssl/openssl_err.h> 25 #include <keymaster/km_openssl/openssl_utils.h> 26 #include <keymaster/serializable.h> 27 28 namespace keymaster { 29 30 inline uint32_t div_round_up(uint32_t dividend, uint32_t divisor) { 31 return (dividend + divisor - 1) / divisor; 32 } 33 34 size_t min(size_t a, size_t b) { 35 return a < b ? a : b; 36 } 37 38 DEFINE_OPENSSL_OBJECT_POINTER(CMAC_CTX) 39 40 keymaster_error_t ckdf(const KeymasterKeyBlob& key, const KeymasterBlob& label, 41 const keymaster_blob_t* context_chunks, size_t num_chunks, 42 KeymasterKeyBlob* output) { 43 // Note: the variables i and L correspond to i and L in the standard. See page 12 of 44 // http://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-108.pdf. 45 46 const uint32_t blocks = div_round_up(output->key_material_size, AES_BLOCK_SIZE); 47 const uint32_t L = output->key_material_size * 8; // bits 48 const uint32_t net_order_L = hton(L); 49 50 CMAC_CTX_Ptr ctx(CMAC_CTX_new()); 51 if (!ctx.get()) return KM_ERROR_MEMORY_ALLOCATION_FAILED; 52 53 auto algo = EVP_aes_128_cbc(); 54 switch (key.key_material_size) { 55 case AES_BLOCK_SIZE: 56 /* Already set */ 57 break; 58 case AES_BLOCK_SIZE * 2: 59 algo = EVP_aes_256_cbc(); 60 break; 61 default: 62 return KM_ERROR_UNSUPPORTED_KEY_SIZE; 63 } 64 65 if (!CMAC_Init(ctx.get(), key.key_material, key.key_material_size, algo, 66 nullptr /* engine */)) { 67 return TranslateLastOpenSslError(); 68 } 69 70 auto output_pos = const_cast<uint8_t*>(output->begin()); 71 memset(output_pos, 0, output->key_material_size); 72 for (uint32_t i = 1; i <= blocks; ++i) { 73 // Data to mac is i || label || 0x00 || context || L, with i and L represented in 32 bits, 74 // in network order. 75 76 // i 77 uint32_t net_order_i = hton(i); 78 if (!CMAC_Update(ctx.get(), reinterpret_cast<uint8_t*>(&net_order_i), 79 sizeof(net_order_i))) { 80 return TranslateLastOpenSslError(); 81 } 82 83 // label 84 if (!CMAC_Update(ctx.get(), label.data, label.data_length)) { 85 return TranslateLastOpenSslError(); 86 } 87 88 // 0x00 89 uint8_t zero = 0; 90 if (!CMAC_Update(ctx.get(), &zero, sizeof(zero))) return TranslateLastOpenSslError(); 91 92 // context 93 for (size_t chunk = 0; chunk < num_chunks; ++chunk) { 94 if (!CMAC_Update(ctx.get(), context_chunks[chunk].data, 95 context_chunks[chunk].data_length)) { 96 return TranslateLastOpenSslError(); 97 } 98 } 99 100 // L 101 uint8_t buf[4]; 102 memcpy(buf, &net_order_L, 4); 103 if (!CMAC_Update(ctx.get(), buf, sizeof(buf))) TranslateLastOpenSslError(); 104 105 size_t out_len; 106 if (output_pos <= output->end() - AES_BLOCK_SIZE) { 107 if (!CMAC_Final(ctx.get(), output_pos, &out_len)) return TranslateLastOpenSslError(); 108 output_pos += out_len; 109 } else { 110 uint8_t cmac[AES_BLOCK_SIZE]; 111 if (!CMAC_Final(ctx.get(), cmac, &out_len)) return TranslateLastOpenSslError(); 112 size_t to_copy = output->end() - output_pos; 113 memcpy(output_pos, cmac, to_copy); 114 output_pos += to_copy; 115 } 116 117 CMAC_Reset(ctx.get()); 118 } 119 assert(output_pos == output->end()); 120 121 return KM_ERROR_OK; 122 } 123 124 } // namespace keymaster 125