Robert Sloan | 2424d84 | 2017-05-01 07:46:28 -0700 | [diff] [blame] | 1 | /* Copyright (c) 2017, Google Inc. |
| 2 | * |
| 3 | * Permission to use, copy, modify, and/or distribute this software for any |
| 4 | * purpose with or without fee is hereby granted, provided that the above |
| 5 | * copyright notice and this permission notice appear in all copies. |
| 6 | * |
| 7 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| 8 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| 9 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
| 10 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| 11 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
| 12 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
| 13 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ |
| 14 | |
| 15 | #include "cavp_test_util.h" |
| 16 | |
| 17 | #include <openssl/bn.h> |
| 18 | #include <openssl/digest.h> |
| 19 | #include <openssl/ec.h> |
| 20 | #include <openssl/nid.h> |
| 21 | |
| 22 | |
| 23 | std::string EncodeHex(const uint8_t *in, size_t in_len) { |
| 24 | static const char kHexDigits[] = "0123456789abcdef"; |
| 25 | std::string ret; |
| 26 | ret.reserve(in_len * 2); |
| 27 | for (size_t i = 0; i < in_len; i++) { |
| 28 | ret += kHexDigits[in[i] >> 4]; |
| 29 | ret += kHexDigits[in[i] & 0xf]; |
| 30 | } |
| 31 | return ret; |
| 32 | } |
| 33 | |
| 34 | const EVP_CIPHER *GetCipher(const std::string &name) { |
| 35 | if (name == "des-cbc") { |
| 36 | return EVP_des_cbc(); |
| 37 | } else if (name == "des-ecb") { |
| 38 | return EVP_des_ecb(); |
| 39 | } else if (name == "des-ede") { |
| 40 | return EVP_des_ede(); |
| 41 | } else if (name == "des-ede3") { |
| 42 | return EVP_des_ede3(); |
| 43 | } else if (name == "des-ede-cbc") { |
| 44 | return EVP_des_ede_cbc(); |
| 45 | } else if (name == "des-ede3-cbc") { |
| 46 | return EVP_des_ede3_cbc(); |
| 47 | } else if (name == "rc4") { |
| 48 | return EVP_rc4(); |
| 49 | } else if (name == "aes-128-ecb") { |
| 50 | return EVP_aes_128_ecb(); |
| 51 | } else if (name == "aes-256-ecb") { |
| 52 | return EVP_aes_256_ecb(); |
| 53 | } else if (name == "aes-128-cbc") { |
| 54 | return EVP_aes_128_cbc(); |
| 55 | } else if (name == "aes-128-gcm") { |
| 56 | return EVP_aes_128_gcm(); |
| 57 | } else if (name == "aes-128-ofb") { |
| 58 | return EVP_aes_128_ofb(); |
| 59 | } else if (name == "aes-192-cbc") { |
| 60 | return EVP_aes_192_cbc(); |
| 61 | } else if (name == "aes-192-ctr") { |
| 62 | return EVP_aes_192_ctr(); |
| 63 | } else if (name == "aes-192-ecb") { |
| 64 | return EVP_aes_192_ecb(); |
| 65 | } else if (name == "aes-256-cbc") { |
| 66 | return EVP_aes_256_cbc(); |
| 67 | } else if (name == "aes-128-ctr") { |
| 68 | return EVP_aes_128_ctr(); |
| 69 | } else if (name == "aes-256-ctr") { |
| 70 | return EVP_aes_256_ctr(); |
| 71 | } else if (name == "aes-256-gcm") { |
| 72 | return EVP_aes_256_gcm(); |
| 73 | } else if (name == "aes-256-ofb") { |
| 74 | return EVP_aes_256_ofb(); |
| 75 | } |
| 76 | return nullptr; |
| 77 | } |
| 78 | |
| 79 | bool CipherOperation(const EVP_CIPHER *cipher, std::vector<uint8_t> *out, |
| 80 | bool encrypt, const std::vector<uint8_t> &key, |
| 81 | const std::vector<uint8_t> &iv, |
| 82 | const std::vector<uint8_t> &in) { |
| 83 | bssl::ScopedEVP_CIPHER_CTX ctx; |
| 84 | if (!EVP_CipherInit_ex(ctx.get(), cipher, nullptr, nullptr, nullptr, |
| 85 | encrypt ? 1 : 0)) { |
| 86 | return false; |
| 87 | } |
| 88 | if (!iv.empty() && iv.size() != EVP_CIPHER_CTX_iv_length(ctx.get())) { |
| 89 | return false; |
| 90 | } |
| 91 | |
| 92 | int result_len1 = 0, result_len2; |
| 93 | *out = std::vector<uint8_t>(in.size()); |
| 94 | if (!EVP_CIPHER_CTX_set_key_length(ctx.get(), key.size()) || |
| 95 | !EVP_CipherInit_ex(ctx.get(), nullptr, nullptr, key.data(), iv.data(), |
| 96 | -1) || |
| 97 | !EVP_CIPHER_CTX_set_padding(ctx.get(), 0) || |
| 98 | !EVP_CipherUpdate(ctx.get(), out->data(), &result_len1, in.data(), |
| 99 | in.size()) || |
| 100 | !EVP_CipherFinal_ex(ctx.get(), out->data() + result_len1, &result_len2)) { |
| 101 | return false; |
| 102 | } |
| 103 | out->resize(result_len1 + result_len2); |
| 104 | |
| 105 | return true; |
| 106 | } |
| 107 | |
| 108 | bool AEADEncrypt(const EVP_AEAD *aead, std::vector<uint8_t> *ct, |
| 109 | std::vector<uint8_t> *tag, size_t tag_len, |
| 110 | const std::vector<uint8_t> &key, |
| 111 | const std::vector<uint8_t> &pt, |
| 112 | const std::vector<uint8_t> &aad, std::vector<uint8_t> *iv) { |
| 113 | bssl::ScopedEVP_AEAD_CTX ctx; |
| 114 | if (!EVP_AEAD_CTX_init_with_direction(ctx.get(), aead, key.data(), key.size(), |
| 115 | tag->size(), evp_aead_seal)) { |
| 116 | return false; |
| 117 | } |
| 118 | |
| 119 | std::vector<uint8_t> out; |
| 120 | out.resize(pt.size() + EVP_AEAD_max_overhead(aead)); |
| 121 | size_t out_len; |
| 122 | if (!EVP_AEAD_CTX_seal(ctx.get(), out.data(), &out_len, out.size(), |
| 123 | nullptr /* iv */, 0 /* iv_len */, pt.data(), pt.size(), |
| 124 | aad.data(), aad.size())) { |
| 125 | return false; |
| 126 | } |
| 127 | |
| 128 | static const size_t iv_len = EVP_AEAD_nonce_length(aead); |
| 129 | iv->assign(out.begin(), out.begin() + iv_len); |
| 130 | ct->assign(out.begin() + iv_len, out.end() - tag_len); |
| 131 | tag->assign(out.end() - tag_len, out.end()); |
| 132 | |
| 133 | return true; |
| 134 | } |
| 135 | |
| 136 | bool AEADDecrypt(const EVP_AEAD *aead, std::vector<uint8_t> *pt, |
| 137 | std::vector<uint8_t> *aad, size_t pt_len, size_t aad_len, |
| 138 | const std::vector<uint8_t> &key, |
| 139 | const std::vector<uint8_t> &ct, |
| 140 | const std::vector<uint8_t> &tag, std::vector<uint8_t> &iv) { |
| 141 | bssl::ScopedEVP_AEAD_CTX ctx; |
| 142 | if (!EVP_AEAD_CTX_init_with_direction(ctx.get(), aead, key.data(), key.size(), |
| 143 | tag.size(), evp_aead_open)) { |
| 144 | return false; |
| 145 | } |
| 146 | std::vector<uint8_t> in = iv; |
| 147 | in.reserve(in.size() + ct.size() + tag.size()); |
| 148 | in.insert(in.end(), ct.begin(), ct.end()); |
| 149 | in.insert(in.end(), tag.begin(), tag.end()); |
| 150 | |
| 151 | pt->resize(pt_len); |
| 152 | aad->resize(aad_len); |
| 153 | size_t out_pt_len; |
| 154 | if (!EVP_AEAD_CTX_open(ctx.get(), pt->data(), &out_pt_len, pt->size(), |
| 155 | nullptr /* iv */, 0 /* iv_len */, in.data(), in.size(), |
| 156 | aad->data(), aad->size()) || |
| 157 | out_pt_len != pt_len) { |
| 158 | return false; |
| 159 | } |
| 160 | return true; |
| 161 | } |
| 162 | |
| 163 | static int HexToBIGNUM(bssl::UniquePtr<BIGNUM> *out, const char *in) { |
| 164 | BIGNUM *raw = NULL; |
| 165 | int ret = BN_hex2bn(&raw, in); |
| 166 | out->reset(raw); |
| 167 | return ret; |
| 168 | } |
| 169 | |
| 170 | bssl::UniquePtr<BIGNUM> GetBIGNUM(FileTest *t, const char *attribute) { |
| 171 | std::string hex; |
| 172 | if (!t->GetAttribute(&hex, attribute)) { |
| 173 | return nullptr; |
| 174 | } |
| 175 | |
| 176 | bssl::UniquePtr<BIGNUM> ret; |
| 177 | if (HexToBIGNUM(&ret, hex.c_str()) != static_cast<int>(hex.size())) { |
| 178 | t->PrintLine("Could not decode '%s'.", hex.c_str()); |
| 179 | return nullptr; |
| 180 | } |
| 181 | return ret; |
| 182 | } |
| 183 | |
| 184 | int GetECGroupNIDFromInstruction(FileTest *t) { |
| 185 | if (t->HasInstruction("P-224")) { |
| 186 | return NID_secp224r1; |
| 187 | } |
| 188 | if (t->HasInstruction("P-256")) { |
| 189 | return NID_X9_62_prime256v1; |
| 190 | } |
| 191 | if (t->HasInstruction("P-384")) { |
| 192 | return NID_secp384r1; |
| 193 | } |
| 194 | if (t->HasInstruction("P-521")) { |
| 195 | return NID_secp521r1; |
| 196 | } |
| 197 | t->PrintLine("No supported group specified."); |
| 198 | return NID_undef; |
| 199 | } |
| 200 | |
| 201 | const EVP_MD *GetDigestFromInstruction(FileTest *t) { |
| 202 | if (t->HasInstruction("SHA-1")) { |
| 203 | return EVP_sha1(); |
| 204 | } |
| 205 | if (t->HasInstruction("SHA-224")) { |
| 206 | return EVP_sha224(); |
| 207 | } |
| 208 | if (t->HasInstruction("SHA-256")) { |
| 209 | return EVP_sha256(); |
| 210 | } |
| 211 | if (t->HasInstruction("SHA-384")) { |
| 212 | return EVP_sha384(); |
| 213 | } |
| 214 | if (t->HasInstruction("SHA-512")) { |
| 215 | return EVP_sha512(); |
| 216 | } |
| 217 | t->PrintLine("No supported digest function specified."); |
| 218 | return nullptr; |
| 219 | } |