Skip to content

Commit 5188ef8

Browse files
Add ACVP support for AES CFB128 (#2861)
1 parent 3d81c17 commit 5188ef8

File tree

6 files changed

+66
-0
lines changed

6 files changed

+66
-0
lines changed

util/fipstools/acvp/ACVP.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ The other commands are as follows. (Note that you only need to implement the com
5353
| AES-CBC-CS3/encrypt | Key, plaintext, IV, num iterations² | Result |
5454
| AES-CCM/open | Tag length, key, ciphertext, nonce, ad | One-byte success flag, plaintext or empty |
5555
| AES-CCM/seal | Tag length, key, plaintext, nonce, ad | Ciphertext |
56+
| AES-CFB128/decrypt | Key, ciphertext, IV, num iterations¹ | Plaintext |
57+
| AES-CFB128/encrypt | Key, plaintexttext, IV, num iterations¹ | Ciphertext |
5658
| AES-CTR/decrypt | Key, ciphertext, initial counter, constant 1 | Plaintext |
5759
| AES-CTR/encrypt | Key, plaintexttext, initial counter, constant 1 | Ciphertext |
5860
| AES-GCM/open | Tag length, key, ciphertext, nonce, ad | One-byte success flag, plaintext or empty |

util/fipstools/acvp/acvptool/subprocess/subprocess.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,9 @@ func NewWithIO(cmd *exec.Cmd, in io.WriteCloser, out io.ReadCloser) *Subprocess
116116
"ACVP-AES-ECB": &blockCipher{"AES", 16, 2, true, false, iterateAES},
117117
"ACVP-AES-CBC": &blockCipher{"AES-CBC", 16, 2, true, true, iterateAESCBC},
118118
"ACVP-AES-CBC-CS3": &blockCipher{"AES-CBC-CS3", 16, 1, false, true, iterateAESCBC},
119+
// NOTE: AES CFB128's ACVP MCT outer loop is the same as AES CBC's
120+
// https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/aes/AESAVS.pdf
121+
"ACVP-AES-CFB128": &blockCipher{"AES-CFB128", 16, 2, true, true, iterateAESCBC},
119122
"ACVP-AES-CTR": &blockCipher{"AES-CTR", 16, 1, false, true, nil},
120123
"ACVP-TDES-ECB": &blockCipher{"3DES-ECB", 8, 3, true, false, iterate3DES},
121124
"ACVP-TDES-CBC": &blockCipher{"3DES-CBC", 8, 3, true, true, iterate3DESCBC},
45.6 KB
Binary file not shown.

util/fipstools/acvp/acvptool/test/tests.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
{"Wrapper": "testmodulewrapper", "In": "vectors/ACVP-AES-CBC-CS3.bz2", "Out": "expected/ACVP-AES-CBC-CS3.bz2"},
44
{"Wrapper": "modulewrapper", "In": "vectors/ACVP-AES-CCM.bz2", "Out": "expected/ACVP-AES-CCM.bz2"},
55
{"Wrapper": "modulewrapper", "In": "vectors/ACVP-AES-CTR.bz2", "Out": "expected/ACVP-AES-CTR.bz2"},
6+
{"Wrapper": "modulewrapper", "In": "vectors/ACVP-AES-CFB128.bz2", "Out": "expected/ACVP-AES-CFB128.bz2"},
67
{"Wrapper": "modulewrapper", "In": "vectors/ACVP-AES-ECB.bz2", "Out": "expected/ACVP-AES-ECB.bz2"},
78
{"Wrapper": "modulewrapper", "In": "vectors/ACVP-AES-GCM.bz2", "Out": "expected/ACVP-AES-GCM.bz2"},
89
{"Wrapper": "modulewrapper", "In": "vectors/ACVP-AES-GMAC.bz2", "Out": "expected/ACVP-AES-GMAC.bz2"},
2.87 KB
Binary file not shown.

util/fipstools/acvp/modulewrapper/modulewrapper.cc

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,12 @@ static bool GetConfig(const Span<const uint8_t> args[],
340340
"direction": ["encrypt", "decrypt"],
341341
"keyLen": [128, 192, 256]
342342
},
343+
{
344+
"algorithm": "ACVP-AES-CFB128",
345+
"revision": "1.0",
346+
"direction": ["encrypt", "decrypt"],
347+
"keyLen": [128, 192, 256]
348+
},
343349
{
344350
"algorithm": "ACVP-AES-GCM",
345351
"revision": "1.0",
@@ -1760,6 +1766,58 @@ static bool AES_CBC(const Span<const uint8_t> args[],
17601766
{Span<const uint8_t>(result), Span<const uint8_t>(prev_result)});
17611767
}
17621768

1769+
template <void (*CipherOp)(const uint8_t *in, uint8_t *out,
1770+
size_t bits, const AES_KEY *key,
1771+
uint8_t *ivec, int *num, int enc),
1772+
int Direction>
1773+
static bool AES_CFB(const Span<const uint8_t> args[],
1774+
ReplyCallback write_reply) {
1775+
AES_KEY key;
1776+
if (AES_set_encrypt_key(args[0].data(), args[0].size() * 8, &key) != 0) {
1777+
return false;
1778+
}
1779+
if (args[1].empty() || args[2].size() != AES_BLOCK_SIZE) {
1780+
return false;
1781+
}
1782+
std::vector<uint8_t> input(args[1].begin(), args[1].end());
1783+
std::vector<uint8_t> iv(args[2].begin(), args[2].end());
1784+
const uint32_t iterations = GetIterations(args[3]);
1785+
1786+
std::vector<uint8_t> result(input.size());
1787+
std::vector<uint8_t> prev_result, prev_input;
1788+
1789+
for (uint32_t j = 0; j < iterations; j++) {
1790+
prev_result = result;
1791+
if (j > 0) {
1792+
if (Direction == AES_ENCRYPT) {
1793+
iv = result;
1794+
} else {
1795+
iv = prev_input;
1796+
}
1797+
}
1798+
1799+
// CipherOp will mutate the given IV, but we need it later.
1800+
uint8_t iv_copy[AES_BLOCK_SIZE];
1801+
memcpy(iv_copy, iv.data(), sizeof(iv_copy));
1802+
int num = 0;
1803+
CipherOp(input.data(), result.data(), input.size(), &key, iv_copy,
1804+
&num, Direction);
1805+
1806+
if (Direction == AES_DECRYPT) {
1807+
prev_input = input;
1808+
}
1809+
1810+
if (j == 0) {
1811+
input = iv;
1812+
} else {
1813+
input = prev_result;
1814+
}
1815+
}
1816+
1817+
return write_reply(
1818+
{Span<const uint8_t>(result), Span<const uint8_t>(prev_result)});
1819+
}
1820+
17631821
static bool AES_CTR(const Span<const uint8_t> args[],
17641822
ReplyCallback write_reply) {
17651823
static const uint32_t kOneIteration = 1;
@@ -3381,6 +3439,8 @@ static struct {
33813439
{"AES-XTS/decrypt", 3, AES_XTS<false>},
33823440
{"AES-CBC/encrypt", 4, AES_CBC<AES_set_encrypt_key, AES_ENCRYPT>},
33833441
{"AES-CBC/decrypt", 4, AES_CBC<AES_set_decrypt_key, AES_DECRYPT>},
3442+
{"AES-CFB128/encrypt", 4, AES_CFB<AES_cfb128_encrypt, AES_ENCRYPT>},
3443+
{"AES-CFB128/decrypt", 4, AES_CFB<AES_cfb128_encrypt, AES_DECRYPT>},
33843444
{"AES-CTR/encrypt", 4, AES_CTR},
33853445
{"AES-CTR/decrypt", 4, AES_CTR},
33863446
{"AES-GCM/seal", 5, AEADSeal<AESGCMSetup>},

0 commit comments

Comments
 (0)