acvp: add 3DES-CBC support
Change-Id: I2e6cc7367b5ca6631329be298fbed7424221a06b
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/43406
Commit-Queue: Adam Langley <agl@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/util/fipstools/acvp/acvptool/subprocess/block.go b/util/fipstools/acvp/acvptool/subprocess/block.go
index 35c2133..3b468c8 100644
--- a/util/fipstools/acvp/acvptool/subprocess/block.go
+++ b/util/fipstools/acvp/acvptool/subprocess/block.go
@@ -203,6 +203,65 @@
return mctResults
}
+// iterate3DESCBC implements "TDES Monte Carlo Test - CBC mode" from the ACVP
+// specification.
+func iterate3DESCBC(transact func(n int, args ...[]byte) ([][]byte, error), encrypt bool, key, input, iv []byte) (mctResults []blockCipherMCTResult) {
+ for i := 0; i < 400; i++ {
+ var iteration blockCipherMCTResult
+ keyHex := hex.EncodeToString(key)
+ iteration.Key1Hex = keyHex[:16]
+ iteration.Key2Hex = keyHex[16:32]
+ iteration.Key3Hex = keyHex[32:]
+
+ if encrypt {
+ iteration.PlaintextHex = hex.EncodeToString(input)
+ } else {
+ iteration.CiphertextHex = hex.EncodeToString(input)
+ }
+ iteration.IVHex = hex.EncodeToString(iv)
+
+ var result, prevResult, prevPrevResult []byte
+ for j := 0; j < 10000; j++ {
+ prevPrevResult = prevResult
+ prevResult = result
+ results, err := transact(1, key, input, iv)
+ if err != nil {
+ panic("block operation failed")
+ }
+ result = results[0]
+
+ if encrypt {
+ if j == 0 {
+ input = iv
+ } else {
+ input = prevResult
+ }
+ iv = result
+ } else {
+ iv = input
+ input = result
+ }
+ }
+
+ if encrypt {
+ iteration.CiphertextHex = hex.EncodeToString(result)
+ } else {
+ iteration.PlaintextHex = hex.EncodeToString(result)
+ }
+
+ keyShuffle3DES(key, result, prevResult, prevPrevResult)
+
+ if encrypt {
+ input = prevResult
+ iv = result
+ }
+
+ mctResults = append(mctResults, iteration)
+ }
+
+ return mctResults
+}
+
// blockCipher implements an ACVP algorithm by making requests to the subprocess
// to encrypt and decrypt with a block cipher.
type blockCipher struct {
diff --git a/util/fipstools/acvp/acvptool/subprocess/subprocess.go b/util/fipstools/acvp/acvptool/subprocess/subprocess.go
index 3c04981..76442fa 100644
--- a/util/fipstools/acvp/acvptool/subprocess/subprocess.go
+++ b/util/fipstools/acvp/acvptool/subprocess/subprocess.go
@@ -80,6 +80,7 @@
"ACVP-AES-CBC": &blockCipher{"AES-CBC", 16, true, true, iterateAESCBC},
"ACVP-AES-CTR": &blockCipher{"AES-CTR", 16, false, true, nil},
"ACVP-TDES-ECB": &blockCipher{"3DES-ECB", 8, true, false, iterate3DES},
+ "ACVP-TDES-CBC": &blockCipher{"3DES-CBC", 8, true, true, iterate3DESCBC},
"ACVP-AES-GCM": &aead{"AES-GCM", false},
"ACVP-AES-CCM": &aead{"AES-CCM", true},
"ACVP-AES-KW": &aead{"AES-KW", false},
diff --git a/util/fipstools/acvp/modulewrapper/modulewrapper.cc b/util/fipstools/acvp/modulewrapper/modulewrapper.cc
index d97ea91..c782f67 100644
--- a/util/fipstools/acvp/modulewrapper/modulewrapper.cc
+++ b/util/fipstools/acvp/modulewrapper/modulewrapper.cc
@@ -259,6 +259,13 @@
"keyingOption": [1]
},
{
+ "algorithm": "ACVP-TDES-CBC",
+ "revision": "1.0",
+ "direction": ["encrypt", "decrypt"],
+ "keyLen": [192],
+ "keyingOption": [1]
+ },
+ {
"algorithm": "HMAC-SHA-1",
"revision": "1.0",
"keyLen": [{
@@ -728,9 +735,9 @@
Span<const uint8_t>(out));
}
-template<bool Encrypt>
+template<bool Encrypt, bool HasIV, const EVP_CIPHER* (*cipher_func)()>
static bool TDES(const Span<const uint8_t> args[]) {
- const EVP_CIPHER *cipher = EVP_des_ede3();
+ const EVP_CIPHER *cipher = cipher_func();
if (args[0].size() != 24) {
fprintf(stderr, "Bad key length %u for 3DES.\n",
@@ -742,14 +749,19 @@
static_cast<unsigned>(args[1].size()));
return false;
}
+ if (HasIV && args[2].size() != EVP_CIPHER_iv_length(cipher)) {
+ fprintf(stderr, "Bad IV length %u for 3DES.\n",
+ static_cast<unsigned>(args[2].size()));
+ return false;
+ }
std::vector<uint8_t> out;
out.resize(args[1].size());
bssl::ScopedEVP_CIPHER_CTX ctx;
int out_len, out_len2;
- if (!EVP_CipherInit_ex(ctx.get(), cipher, nullptr, args[0].data(), nullptr,
- Encrypt ? 1 : 0) ||
+ if (!EVP_CipherInit_ex(ctx.get(), cipher, nullptr, args[0].data(),
+ HasIV ? args[2].data() : nullptr, Encrypt ? 1 : 0) ||
!EVP_CIPHER_CTX_set_padding(ctx.get(), 0) ||
!EVP_CipherUpdate(ctx.get(), out.data(), &out_len, args[1].data(),
args[1].size()) ||
@@ -1016,8 +1028,10 @@
{"AES-KWP/open", 5, AESPaddedKeyWrapOpen},
{"AES-CCM/seal", 5, AEADSeal<AESCCMSetup>},
{"AES-CCM/open", 5, AEADOpen<AESCCMSetup>},
- {"3DES-ECB/encrypt", 2, TDES<true>},
- {"3DES-ECB/decrypt", 2, TDES<false>},
+ {"3DES-ECB/encrypt", 2, TDES<true, false, EVP_des_ede3>},
+ {"3DES-ECB/decrypt", 2, TDES<false, false, EVP_des_ede3>},
+ {"3DES-CBC/encrypt", 3, TDES<true, true, EVP_des_ede3_cbc>},
+ {"3DES-CBC/decrypt", 3, TDES<false, true, EVP_des_ede3_cbc>},
{"HMAC-SHA-1", 2, HMAC<EVP_sha1>},
{"HMAC-SHA2-224", 2, HMAC<EVP_sha224>},
{"HMAC-SHA2-256", 2, HMAC<EVP_sha256>},