Bläddra i källkod

Add a Wycheproof driver for AES-CBC.

Change-Id: I782ea51e1db8d05f552832a7c6910954fa2dda5f
Reviewed-on: https://boringssl-review.googlesource.com/27924
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
kris/onging/CECPQ3_patch15
David Benjamin 6 år sedan
committed by CQ bot account: commit-bot@chromium.org
förälder
incheckning
8e75ae4880
6 ändrade filer med 1919 tillägg och 25 borttagningar
  1. +97
    -22
      crypto/cipher_extra/cipher_test.cc
  2. +4
    -0
      crypto/fipsmodule/cipher/cipher.c
  3. +4
    -0
      include/openssl/cipher.h
  4. +1
    -0
      sources.cmake
  5. +1812
    -0
      third_party/wycheproof/aes_cbc_pkcs5_test.txt
  6. +1
    -3
      third_party/wycheproof/convert_wycheproof.go

+ 97
- 22
crypto/cipher_extra/cipher_test.cc Visa fil

@@ -51,9 +51,11 @@
* ====================================================================
*/

#include <limits.h>
#include <stdlib.h>
#include <string.h>

#include <algorithm>
#include <string>
#include <vector>

@@ -61,9 +63,11 @@

#include <openssl/cipher.h>
#include <openssl/err.h>
#include <openssl/span.h>

#include "../test/file_test.h"
#include "../test/test_util.h"
#include "../test/wycheproof_util.h"


static const EVP_CIPHER *GetCipher(const std::string &name) {
@@ -111,6 +115,38 @@ static const EVP_CIPHER *GetCipher(const std::string &name) {
return nullptr;
}

static bool DoCipher(EVP_CIPHER_CTX *ctx, std::vector<uint8_t> *out,
bssl::Span<const uint8_t> in, size_t chunk) {
size_t max_out = in.size();
if ((EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_NO_PADDING) == 0 &&
EVP_CIPHER_CTX_encrypting(ctx)) {
unsigned block_size = EVP_CIPHER_CTX_block_size(ctx);
max_out += block_size - (max_out % block_size);
}
out->resize(max_out);

size_t total = 0;
int len;
while (!in.empty()) {
size_t todo = chunk == 0 ? in.size() : std::min(in.size(), chunk);
EXPECT_LE(todo, static_cast<size_t>(INT_MAX));
if (!EVP_CipherUpdate(ctx, out->data() + total, &len, in.data(),
static_cast<int>(todo))) {
return false;
}
EXPECT_GE(len, 0);
total += static_cast<size_t>(len);
in = in.subspan(todo);
}
if (!EVP_CipherFinal_ex(ctx, out->data() + total, &len)) {
return false;
}
EXPECT_GE(len, 0);
total += static_cast<size_t>(len);
out->resize(total);
return true;
}

static void TestOperation(FileTest *t, const EVP_CIPHER *cipher, bool encrypt,
size_t chunk_size, const std::vector<uint8_t> &key,
const std::vector<uint8_t> &iv,
@@ -146,9 +182,7 @@ static void TestOperation(FileTest *t, const EVP_CIPHER *cipher, bool encrypt,
}
// The ciphers are run with no padding. For each of the ciphers we test, the
// output size matches the input size.
std::vector<uint8_t> result(in->size());
ASSERT_EQ(in->size(), out->size());
int unused, result_len1 = 0, result_len2;
ASSERT_TRUE(EVP_CIPHER_CTX_set_key_length(ctx.get(), key.size()));
ASSERT_TRUE(EVP_CipherInit_ex(ctx.get(), nullptr, nullptr, key.data(),
iv.data(), -1));
@@ -156,30 +190,13 @@ static void TestOperation(FileTest *t, const EVP_CIPHER *cipher, bool encrypt,
// parameters are NULL, so it is important to skip the |in| and |aad|
// |EVP_CipherUpdate| calls when empty.
if (!aad.empty()) {
int unused;
ASSERT_TRUE(
EVP_CipherUpdate(ctx.get(), nullptr, &unused, aad.data(), aad.size()));
}
ASSERT_TRUE(EVP_CIPHER_CTX_set_padding(ctx.get(), 0));
if (chunk_size != 0) {
for (size_t i = 0; i < in->size();) {
size_t todo = chunk_size;
if (i + todo > in->size()) {
todo = in->size() - i;
}

int len;
ASSERT_TRUE(EVP_CipherUpdate(ctx.get(), result.data() + result_len1, &len,
in->data() + i, todo));
result_len1 += len;
i += todo;
}
} else if (!in->empty()) {
ASSERT_TRUE(EVP_CipherUpdate(ctx.get(), result.data(), &result_len1,
in->data(), in->size()));
}
ASSERT_TRUE(
EVP_CipherFinal_ex(ctx.get(), result.data() + result_len1, &result_len2));
result.resize(result_len1 + result_len2);
std::vector<uint8_t> result;
ASSERT_TRUE(DoCipher(ctx.get(), &result, *in, chunk_size));
EXPECT_EQ(Bytes(*out), Bytes(result));
if (encrypt && is_aead) {
uint8_t rtag[16];
@@ -285,3 +302,61 @@ TEST(CipherTest, CAVP_TDES_CBC) {
TEST(CipherTest, CAVP_TDES_ECB) {
FileTestGTest("crypto/cipher_extra/test/nist_cavp/tdes_ecb.txt", TestCipher);
}

TEST(CipherTest, WycheproofAESCBC) {
FileTestGTest("third_party/wycheproof/aes_cbc_pkcs5_test.txt",
[](FileTest *t) {
t->IgnoreInstruction("type");
t->IgnoreInstruction("ivSize");

std::string key_size;
ASSERT_TRUE(t->GetInstruction(&key_size, "keySize"));
const EVP_CIPHER *cipher;
switch (atoi(key_size.c_str())) {
case 128:
cipher = EVP_aes_128_cbc();
break;
case 192:
cipher = EVP_aes_192_cbc();
break;
case 256:
cipher = EVP_aes_256_cbc();
break;
default:
FAIL() << "Unsupported key size: " << key_size;
}

std::vector<uint8_t> key, iv, msg, ct;
ASSERT_TRUE(t->GetBytes(&key, "key"));
ASSERT_TRUE(t->GetBytes(&iv, "iv"));
ASSERT_TRUE(t->GetBytes(&msg, "msg"));
ASSERT_TRUE(t->GetBytes(&ct, "ct"));
ASSERT_EQ(EVP_CIPHER_key_length(cipher), key.size());
ASSERT_EQ(EVP_CIPHER_iv_length(cipher), iv.size());
WycheproofResult result;
ASSERT_TRUE(GetWycheproofResult(t, &result));

bssl::ScopedEVP_CIPHER_CTX ctx;
std::vector<uint8_t> out;
const std::vector<size_t> chunk_sizes = {0, 1, 2, 5, 7, 8, 9, 15, 16,
17, 31, 32, 33, 63, 64, 65, 512};
for (size_t chunk : chunk_sizes) {
SCOPED_TRACE(chunk);
if (result == WycheproofResult::kValid) {
ASSERT_TRUE(EVP_DecryptInit_ex(ctx.get(), cipher, nullptr, key.data(),
iv.data()));
ASSERT_TRUE(DoCipher(ctx.get(), &out, ct, chunk));
EXPECT_EQ(Bytes(msg), Bytes(out));

ASSERT_TRUE(EVP_EncryptInit_ex(ctx.get(), cipher, nullptr, key.data(),
iv.data()));
ASSERT_TRUE(DoCipher(ctx.get(), &out, msg, chunk));
EXPECT_EQ(Bytes(ct), Bytes(out));
} else {
ASSERT_TRUE(EVP_DecryptInit_ex(ctx.get(), cipher, nullptr, key.data(),
iv.data()));
EXPECT_FALSE(DoCipher(ctx.get(), &out, ct, chunk));
}
}
});
}

+ 4
- 0
crypto/fipsmodule/cipher/cipher.c Visa fil

@@ -496,6 +496,10 @@ int EVP_CIPHER_CTX_nid(const EVP_CIPHER_CTX *ctx) {
return ctx->cipher->nid;
}

int EVP_CIPHER_CTX_encrypting(const EVP_CIPHER_CTX *ctx) {
return ctx->encrypt;
}

unsigned EVP_CIPHER_CTX_block_size(const EVP_CIPHER_CTX *ctx) {
return ctx->cipher->block_size;
}


+ 4
- 0
include/openssl/cipher.h Visa fil

@@ -243,6 +243,10 @@ OPENSSL_EXPORT const EVP_CIPHER *EVP_CIPHER_CTX_cipher(
// configured.
OPENSSL_EXPORT int EVP_CIPHER_CTX_nid(const EVP_CIPHER_CTX *ctx);

// EVP_CIPHER_CTX_encrypting returns one if |ctx| is configured for encryption
// and zero otherwise.
OPENSSL_EXPORT int EVP_CIPHER_CTX_encrypting(const EVP_CIPHER_CTX *ctx);

// EVP_CIPHER_CTX_block_size returns the block size, in bytes, of the cipher
// underlying |ctx|, or one if the cipher is a stream cipher. It will crash if
// no cipher has been configured.


+ 1
- 0
sources.cmake Visa fil

@@ -59,6 +59,7 @@ set(
crypto/x509/some_names1.pem
crypto/x509/some_names2.pem
crypto/x509/some_names3.pem
third_party/wycheproof/aes_cbc_pkcs5_test.txt
third_party/wycheproof/aes_gcm_siv_test.txt
third_party/wycheproof/aes_gcm_test.txt
third_party/wycheproof/chacha20_poly1305_test.txt


+ 1812
- 0
third_party/wycheproof/aes_cbc_pkcs5_test.txt
Filskillnaden har hållits tillbaka eftersom den är för stor
Visa fil


+ 1
- 3
third_party/wycheproof/convert_wycheproof.go Visa fil

@@ -227,6 +227,7 @@ func convertWycheproof(jsonPath, txtPath string) error {

func main() {
jsonPaths := []string{
"aes_cbc_pkcs5_test.json",
"aes_gcm_siv_test.json",
"aes_gcm_test.json",
"chacha20_poly1305_test.json",
@@ -241,9 +242,6 @@ func main() {
"eddsa_test.json",
"rsa_signature_test.json",
"x25519_test.json",

// TODO(davidben): The following tests still need test drivers.
// "aes_cbc_pkcs5_test.json",
}
for _, jsonPath := range jsonPaths {
if !strings.HasSuffix(jsonPath, ".json") {


Laddar…
Avbryt
Spara