acvp: add AES-CCM support.

Change-Id: Ia8cbfd0b8f0f3932aea20e801e031d8df318f386
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/43286
Commit-Queue: Adam Langley <agl@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
chromium-5359
Adam Langley 4 years ago committed by CQ bot account: commit-bot@chromium.org
parent 56b28d8446
commit f94e6d7f9d
  1. 52
      util/fipstools/acvp/acvptool/subprocess/aead.go
  2. 7
      util/fipstools/acvp/acvptool/subprocess/subprocess.go
  3. 65
      util/fipstools/acvp/modulewrapper/modulewrapper.cc

@ -23,7 +23,8 @@ import (
// aead implements an ACVP algorithm by making requests to the subprocess
// to encrypt and decrypt with an AEAD.
type aead struct {
algo string
algo string
tagMergedWithCiphertext bool
}
type aeadVectorSet struct {
@ -120,18 +121,6 @@ func (a *aead) Process(vectorSet []byte, m Transactable) (interface{}, error) {
return nil, fmt.Errorf("failed to decode aad in test case %d/%d: %s", group.ID, test.ID, err)
}
var tag []byte
if !encrypt {
if tag, err = hex.DecodeString(test.TagHex); err != nil {
return nil, fmt.Errorf("failed to decode tag in test case %d/%d: %s", group.ID, test.ID, err)
}
if len(tag) != tagBytes {
return nil, fmt.Errorf("tag in test case %d/%d is %d bytes long, but should be %d", group.ID, test.ID, len(tag), tagBytes)
}
} else if len(test.TagHex) != 0 {
return nil, fmt.Errorf("test case %d/%d has unexpected tag input", group.ID, test.ID)
}
var inputHex, otherHex string
if encrypt {
inputHex, otherHex = test.PlaintextHex, test.CiphertextHex
@ -148,6 +137,27 @@ func (a *aead) Process(vectorSet []byte, m Transactable) (interface{}, error) {
return nil, fmt.Errorf("failed to decode hex in test case %d/%d: %s", group.ID, test.ID, err)
}
var tag []byte
if a.tagMergedWithCiphertext {
if len(test.TagHex) != 0 {
return nil, fmt.Errorf("test case %d/%d has unexpected tag input (should be merged into ciphertext)", group.ID, test.ID)
}
if !encrypt && len(input) < tagBytes {
return nil, fmt.Errorf("test case %d/%d has ciphertext shorter than the tag, but the tag should be included in it", group.ID, test.ID)
}
} else {
if !encrypt {
if tag, err = hex.DecodeString(test.TagHex); err != nil {
return nil, fmt.Errorf("failed to decode tag in test case %d/%d: %s", group.ID, test.ID, err)
}
if len(tag) != tagBytes {
return nil, fmt.Errorf("tag in test case %d/%d is %d bytes long, but should be %d", group.ID, test.ID, len(tag), tagBytes)
}
} else if len(test.TagHex) != 0 {
return nil, fmt.Errorf("test case %d/%d has unexpected tag input", group.ID, test.ID)
}
}
testResp := aeadTestResponse{ID: test.ID}
if encrypt {
@ -160,12 +170,16 @@ func (a *aead) Process(vectorSet []byte, m Transactable) (interface{}, error) {
return nil, fmt.Errorf("ciphertext from subprocess for test case %d/%d is shorter than the tag (%d vs %d)", group.ID, test.ID, len(result[0]), tagBytes)
}
ciphertext := result[0][:len(result[0])-tagBytes]
ciphertextHex := hex.EncodeToString(ciphertext)
tag := result[0][len(result[0])-tagBytes:]
testResp.CiphertextHex = &ciphertextHex
testResp.TagHex = hex.EncodeToString(tag)
if a.tagMergedWithCiphertext {
ciphertextHex := hex.EncodeToString(result[0])
testResp.CiphertextHex = &ciphertextHex
} else {
ciphertext := result[0][:len(result[0])-tagBytes]
ciphertextHex := hex.EncodeToString(ciphertext)
testResp.CiphertextHex = &ciphertextHex
tag := result[0][len(result[0])-tagBytes:]
testResp.TagHex = hex.EncodeToString(tag)
}
} else {
result, err := m.Transact(op, 2, uint32le(uint32(tagBytes)), key, append(input, tag...), nonce, aad)
if err != nil {

@ -79,9 +79,10 @@ func NewWithIO(cmd *exec.Cmd, in io.WriteCloser, out io.ReadCloser) *Subprocess
"ACVP-AES-ECB": &blockCipher{"AES", 16, true, false},
"ACVP-AES-CBC": &blockCipher{"AES-CBC", 16, true, true},
"ACVP-AES-CTR": &blockCipher{"AES-CTR", 16, false, true},
"ACVP-AES-GCM": &aead{"AES-GCM"},
"ACVP-AES-KW": &aead{"AES-KW"},
"ACVP-AES-KWP": &aead{"AES-KWP"},
"ACVP-AES-GCM": &aead{"AES-GCM", false},
"ACVP-AES-CCM": &aead{"AES-CCM", true},
"ACVP-AES-KW": &aead{"AES-KW", false},
"ACVP-AES-KWP": &aead{"AES-KWP", false},
"HMAC-SHA-1": &hmacPrimitive{"HMAC-SHA-1", 20},
"HMAC-SHA2-224": &hmacPrimitive{"HMAC-SHA2-224", 28},
"HMAC-SHA2-256": &hmacPrimitive{"HMAC-SHA2-256", 32},

@ -235,6 +235,21 @@ static bool GetConfig(const Span<const uint8_t> args[]) {
],
"payloadLen": [{"min": 8, "max": 1024, "increment": 8}]
},
{
"algorithm": "ACVP-AES-CCM",
"revision": "1.0",
"direction": [
"encrypt",
"decrypt"
],
"keyLen": [
128
],
"payloadLen": [{"min": 0, "max": 256, "increment": 8}],
"ivLen": [104],
"tagLen": [32],
"aadLen": [{"min": 0, "max": 1024, "increment": 8}]
},
{
"algorithm": "HMAC-SHA-1",
"revision": "1.0",
@ -495,7 +510,41 @@ static bool AESGCMSetup(EVP_AEAD_CTX *ctx, Span<const uint8_t> tag_len_span,
return true;
}
static bool AESGCMSeal(const Span<const uint8_t> args[]) {
static bool AESCCMSetup(EVP_AEAD_CTX *ctx, Span<const uint8_t> tag_len_span,
Span<const uint8_t> key) {
uint32_t tag_len_32;
if (tag_len_span.size() != sizeof(tag_len_32)) {
fprintf(stderr, "Tag size value is %u bytes, not an uint32_t\n",
static_cast<unsigned>(tag_len_span.size()));
return false;
}
memcpy(&tag_len_32, tag_len_span.data(), sizeof(tag_len_32));
if (tag_len_32 != 4) {
fprintf(stderr, "AES-CCM only supports 4-byte tags, but %u was requested\n",
static_cast<unsigned>(tag_len_32));
return false;
}
if (key.size() != 16) {
fprintf(stderr,
"AES-CCM only supports 128-bit keys, but %u bits were given\n",
static_cast<unsigned>(key.size() * 8));
return false;
}
if (!EVP_AEAD_CTX_init(ctx, EVP_aead_aes_128_ccm_bluetooth(), key.data(),
key.size(), tag_len_32, nullptr)) {
fprintf(stderr, "Failed to setup AES-CCM with tag length %u\n",
static_cast<unsigned>(tag_len_32));
return false;
}
return true;
}
template <bool (*SetupFunc)(EVP_AEAD_CTX *ctx, Span<const uint8_t> tag_len_span,
Span<const uint8_t> key)>
static bool AEADSeal(const Span<const uint8_t> args[]) {
Span<const uint8_t> tag_len_span = args[0];
Span<const uint8_t> key = args[1];
Span<const uint8_t> plaintext = args[2];
@ -503,7 +552,7 @@ static bool AESGCMSeal(const Span<const uint8_t> args[]) {
Span<const uint8_t> ad = args[4];
bssl::ScopedEVP_AEAD_CTX ctx;
if (!AESGCMSetup(ctx.get(), tag_len_span, key)) {
if (!SetupFunc(ctx.get(), tag_len_span, key)) {
return false;
}
@ -523,7 +572,9 @@ static bool AESGCMSeal(const Span<const uint8_t> args[]) {
return WriteReply(STDOUT_FILENO, Span<const uint8_t>(out));
}
static bool AESGCMOpen(const Span<const uint8_t> args[]) {
template <bool (*SetupFunc)(EVP_AEAD_CTX *ctx, Span<const uint8_t> tag_len_span,
Span<const uint8_t> key)>
static bool AEADOpen(const Span<const uint8_t> args[]) {
Span<const uint8_t> tag_len_span = args[0];
Span<const uint8_t> key = args[1];
Span<const uint8_t> ciphertext = args[2];
@ -531,7 +582,7 @@ static bool AESGCMOpen(const Span<const uint8_t> args[]) {
Span<const uint8_t> ad = args[4];
bssl::ScopedEVP_AEAD_CTX ctx;
if (!AESGCMSetup(ctx.get(), tag_len_span, key)) {
if (!SetupFunc(ctx.get(), tag_len_span, key)) {
return false;
}
@ -916,12 +967,14 @@ static constexpr struct {
{"AES-CBC/decrypt", 3, AES_CBC<AES_set_decrypt_key, AES_DECRYPT>},
{"AES-CTR/encrypt", 3, AES_CTR},
{"AES-CTR/decrypt", 3, AES_CTR},
{"AES-GCM/seal", 5, AESGCMSeal},
{"AES-GCM/open", 5, AESGCMOpen},
{"AES-GCM/seal", 5, AEADSeal<AESGCMSetup>},
{"AES-GCM/open", 5, AEADOpen<AESGCMSetup>},
{"AES-KW/seal", 5, AESKeyWrapSeal},
{"AES-KW/open", 5, AESKeyWrapOpen},
{"AES-KWP/seal", 5, AESPaddedKeyWrapSeal},
{"AES-KWP/open", 5, AESPaddedKeyWrapOpen},
{"AES-CCM/seal", 5, AEADSeal<AESCCMSetup>},
{"AES-CCM/open", 5, AEADOpen<AESCCMSetup>},
{"HMAC-SHA-1", 2, HMAC<EVP_sha1>},
{"HMAC-SHA2-224", 2, HMAC<EVP_sha224>},
{"HMAC-SHA2-256", 2, HMAC<EVP_sha256>},

Loading…
Cancel
Save