@@ -24,6 +24,8 @@ import (
24
24
"crypto/elliptic"
25
25
"crypto/internal/cryptotest"
26
26
"crypto/internal/fips140"
27
+ "crypto/internal/fips140/aes"
28
+ "crypto/internal/fips140/aes/gcm"
27
29
"crypto/internal/fips140/ecdsa"
28
30
"crypto/internal/fips140/ed25519"
29
31
"crypto/internal/fips140/edwards25519"
@@ -82,6 +84,13 @@ const (
82
84
ecdsaSigTypeDeterministic
83
85
)
84
86
87
+ type aesDirection int
88
+
89
+ const (
90
+ aesEncrypt aesDirection = iota
91
+ aesDecrypt
92
+ )
93
+
85
94
var (
86
95
// SHA2 algorithm capabilities:
87
96
// https://pages.nist.gov/ACVP/draft-celi-acvp-sha.html#section-7.2
97
106
// https://pages.nist.gov/ACVP/draft-celi-acvp-eddsa.html#section-7
98
107
// ECDSA and DetECDSA algorithm capabilities:
99
108
// https://pages.nist.gov/ACVP/draft-fussell-acvp-ecdsa.html#section-7
109
+ // AES algorithm capabilities:
110
+ // https://pages.nist.gov/ACVP/draft-celi-acvp-symmetric.html#section-7.3
100
111
//go:embed acvp_capabilities.json
101
112
capabilitiesJson []byte
102
113
@@ -169,6 +180,15 @@ var (
169
180
"ECDSA/sigGen" : cmdEcdsaSigGenAft (ecdsaSigTypeNormal ),
170
181
"ECDSA/sigVer" : cmdEcdsaSigVerAft (),
171
182
"DetECDSA/sigGen" : cmdEcdsaSigGenAft (ecdsaSigTypeDeterministic ),
183
+
184
+ "AES-CBC/encrypt" : cmdAesCbc (aesEncrypt ),
185
+ "AES-CBC/decrypt" : cmdAesCbc (aesDecrypt ),
186
+ "AES-CTR/encrypt" : cmdAesCtr (aesEncrypt ),
187
+ "AES-CTR/decrypt" : cmdAesCtr (aesDecrypt ),
188
+ "AES-GCM/seal" : cmdAesGcmSeal (false ),
189
+ "AES-GCM/open" : cmdAesGcmOpen (false ),
190
+ "AES-GCM-randnonce/seal" : cmdAesGcmSeal (true ),
191
+ "AES-GCM-randnonce/open" : cmdAesGcmOpen (true ),
172
192
}
173
193
)
174
194
@@ -961,6 +981,179 @@ func lookupCurve(name string) (elliptic.Curve, error) {
961
981
return c , nil
962
982
}
963
983
984
+ func cmdAesCbc (direction aesDirection ) command {
985
+ return command {
986
+ requiredArgs : 4 , // Key, ciphertext or plaintext, IV, num iterations
987
+ handler : func (args [][]byte ) ([][]byte , error ) {
988
+ if direction != aesEncrypt && direction != aesDecrypt {
989
+ panic ("invalid AES direction" )
990
+ }
991
+
992
+ key := args [0 ]
993
+ input := args [1 ]
994
+ iv := args [2 ]
995
+ numIterations := binary .LittleEndian .Uint32 (args [3 ])
996
+
997
+ blockCipher , err := aes .New (key )
998
+ if err != nil {
999
+ return nil , fmt .Errorf ("creating AES block cipher with key len %d: %w" , len (key ), err )
1000
+ }
1001
+
1002
+ if len (input )% blockCipher .BlockSize () != 0 || len (input ) == 0 {
1003
+ return nil , fmt .Errorf ("invalid ciphertext/plaintext size %d: not a multiple of block size %d" ,
1004
+ len (input ), blockCipher .BlockSize ())
1005
+ }
1006
+
1007
+ if blockCipher .BlockSize () != len (iv ) {
1008
+ return nil , fmt .Errorf ("invalid IV size: expected %d, got %d" , blockCipher .BlockSize (), len (iv ))
1009
+ }
1010
+
1011
+ result := make ([]byte , len (input ))
1012
+ prevResult := make ([]byte , len (input ))
1013
+ prevInput := make ([]byte , len (input ))
1014
+
1015
+ for i := uint32 (0 ); i < numIterations ; i ++ {
1016
+ copy (prevResult , result )
1017
+
1018
+ if i > 0 {
1019
+ if direction == aesEncrypt {
1020
+ copy (iv , result )
1021
+ } else {
1022
+ copy (iv , prevInput )
1023
+ }
1024
+ }
1025
+
1026
+ if direction == aesEncrypt {
1027
+ cbcEnc := aes .NewCBCEncrypter (blockCipher , [16 ]byte (iv ))
1028
+ cbcEnc .CryptBlocks (result , input )
1029
+ } else {
1030
+ cbcDec := aes .NewCBCDecrypter (blockCipher , [16 ]byte (iv ))
1031
+ cbcDec .CryptBlocks (result , input )
1032
+ }
1033
+
1034
+ if direction == aesDecrypt {
1035
+ copy (prevInput , input )
1036
+ }
1037
+
1038
+ if i == 0 {
1039
+ copy (input , iv )
1040
+ } else {
1041
+ copy (input , prevResult )
1042
+ }
1043
+ }
1044
+
1045
+ return [][]byte {result , prevResult }, nil
1046
+ },
1047
+ }
1048
+ }
1049
+
1050
+ func cmdAesCtr (direction aesDirection ) command {
1051
+ return command {
1052
+ requiredArgs : 4 , // Key, ciphertext or plaintext, initial counter, num iterations (constant 1)
1053
+ handler : func (args [][]byte ) ([][]byte , error ) {
1054
+ if direction != aesEncrypt && direction != aesDecrypt {
1055
+ panic ("invalid AES direction" )
1056
+ }
1057
+
1058
+ key := args [0 ]
1059
+ input := args [1 ]
1060
+ iv := args [2 ]
1061
+ numIterations := binary .LittleEndian .Uint32 (args [3 ])
1062
+ if numIterations != 1 {
1063
+ return nil , fmt .Errorf ("invalid num iterations: expected 1, got %d" , numIterations )
1064
+ }
1065
+
1066
+ if len (iv ) != aes .BlockSize {
1067
+ return nil , fmt .Errorf ("invalid IV size: expected %d, got %d" , aes .BlockSize , len (iv ))
1068
+ }
1069
+
1070
+ blockCipher , err := aes .New (key )
1071
+ if err != nil {
1072
+ return nil , fmt .Errorf ("creating AES block cipher with key len %d: %w" , len (key ), err )
1073
+ }
1074
+
1075
+ result := make ([]byte , len (input ))
1076
+ stream := aes .NewCTR (blockCipher , iv )
1077
+ stream .XORKeyStream (result , input )
1078
+
1079
+ return [][]byte {result }, nil
1080
+ },
1081
+ }
1082
+ }
1083
+
1084
+ func cmdAesGcmSeal (randNonce bool ) command {
1085
+ return command {
1086
+ requiredArgs : 5 , // tag len, key, plaintext, nonce (empty for randNonce), additional data
1087
+ handler : func (args [][]byte ) ([][]byte , error ) {
1088
+ tagLen := binary .LittleEndian .Uint32 (args [0 ])
1089
+ key := args [1 ]
1090
+ plaintext := args [2 ]
1091
+ nonce := args [3 ]
1092
+ additionalData := args [4 ]
1093
+
1094
+ blockCipher , err := aes .New (key )
1095
+ if err != nil {
1096
+ return nil , fmt .Errorf ("creating AES block cipher with key len %d: %w" , len (key ), err )
1097
+ }
1098
+
1099
+ aesGCM , err := gcm .New (blockCipher , 12 , int (tagLen ))
1100
+ if err != nil {
1101
+ return nil , fmt .Errorf ("creating AES-GCM with tag len %d: %w" , tagLen , err )
1102
+ }
1103
+
1104
+ var ct []byte
1105
+ if ! randNonce {
1106
+ ct = aesGCM .Seal (nil , nonce , plaintext , additionalData )
1107
+ } else {
1108
+ var internalNonce [12 ]byte
1109
+ ct = make ([]byte , len (plaintext )+ 16 )
1110
+ gcm .SealWithRandomNonce (aesGCM , internalNonce [:], ct , plaintext , additionalData )
1111
+ // acvptool expects the internally generated nonce to be appended to the end of the ciphertext.
1112
+ ct = append (ct , internalNonce [:]... )
1113
+ }
1114
+
1115
+ return [][]byte {ct }, nil
1116
+ },
1117
+ }
1118
+ }
1119
+
1120
+ func cmdAesGcmOpen (randNonce bool ) command {
1121
+ return command {
1122
+ requiredArgs : 5 , // tag len, key, ciphertext, nonce (empty for randNonce), additional data
1123
+ handler : func (args [][]byte ) ([][]byte , error ) {
1124
+
1125
+ tagLen := binary .LittleEndian .Uint32 (args [0 ])
1126
+ key := args [1 ]
1127
+ ciphertext := args [2 ]
1128
+ nonce := args [3 ]
1129
+ additionalData := args [4 ]
1130
+
1131
+ blockCipher , err := aes .New (key )
1132
+ if err != nil {
1133
+ return nil , fmt .Errorf ("creating AES block cipher with key len %d: %w" , len (key ), err )
1134
+ }
1135
+
1136
+ aesGCM , err := gcm .New (blockCipher , 12 , int (tagLen ))
1137
+ if err != nil {
1138
+ return nil , fmt .Errorf ("creating AES-GCM with tag len %d: %w" , tagLen , err )
1139
+ }
1140
+
1141
+ if randNonce {
1142
+ // for randNonce tests acvptool appends the nonce to the end of the ciphertext.
1143
+ nonce = ciphertext [len (ciphertext )- 12 :]
1144
+ ciphertext = ciphertext [:len (ciphertext )- 12 ]
1145
+ }
1146
+
1147
+ pt , err := aesGCM .Open (nil , nonce , ciphertext , additionalData )
1148
+ if err != nil {
1149
+ return [][]byte {{0 }, nil }, nil
1150
+ }
1151
+
1152
+ return [][]byte {{1 }, pt }, nil
1153
+ },
1154
+ }
1155
+ }
1156
+
964
1157
func TestACVP (t * testing.T ) {
965
1158
testenv .SkipIfShortAndSlow (t )
966
1159
0 commit comments