github.com/trustbloc/kms-go@v1.1.2/crypto/tinkcrypto/primitive/aead/subtle/aes_cbc_test.go (about) 1 /* 2 Copyright SecureKey Technologies Inc. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package subtle_test 8 9 import ( 10 "crypto/aes" 11 "encoding/base64" 12 "encoding/hex" 13 "fmt" 14 "testing" 15 16 josecipher "github.com/go-jose/go-jose/v3/cipher" 17 "github.com/google/tink/go/subtle/random" 18 "github.com/stretchr/testify/require" 19 20 "github.com/trustbloc/kms-go/crypto/tinkcrypto/primitive/aead/subtle" 21 ) 22 23 func TestNewAESCBC(t *testing.T) { 24 key := make([]byte, 64) 25 26 // Test various key sizes with a fixed IV size. 27 for i := 0; i < 64; i++ { 28 k := key[:i] 29 c, err := subtle.NewAESCBC(k) 30 31 switch len(k) { 32 case 16, 24, 32: 33 // Valid key sizes. 34 require.NoError(t, err, "want: valid cipher (key size=%d), got: error %v", len(k), err) 35 36 // Verify that the struct contents are correctly set. 37 require.Equal(t, len(k), len(c.Key), "want: key size=%d, got: key size=%d", len(k), len(c.Key)) 38 default: 39 // Invalid key sizes. 40 require.EqualError(t, err, fmt.Sprintf("aes_cbc: NewAESCBC() invalid AES key size; want 16, 24 or 32,"+ 41 " got %d", i)) 42 } 43 } 44 } 45 46 func TestNistTestVector(t *testing.T) { 47 // NIST SP 800-38A pp 27 48 key, err := hex.DecodeString("2b7e151628aed2a6abf7158809cf4f3c") 49 require.NoError(t, err) 50 51 // NIST IV 52 iv := "000102030405060708090a0b0c0d0e0f" 53 // NIST ciphertext blocks 54 c := "7649abac8119b246cee98e9b12e9197d" + 55 "5086cb9b507219ee95db113a917678b2" + 56 "73bed6b8e3c1743b7116e69e22229516" + 57 "3ff1caa1681fac09120eca307586e1a7" 58 ciphertext, err := hex.DecodeString(iv + c) 59 require.NoError(t, err) 60 61 // NIST plaintext blocks 62 p := "6bc1bee22e409f96e93d7e117393172a" + 63 "ae2d8a571e03ac9c9eb76fac45af8e51" + 64 "30c81c46a35ce411e5fbc1191a0a52ef" + 65 "f69f2445df4f9b17ad2b417be66c3710" 66 message, err := hex.DecodeString(p) 67 require.NoError(t, err) 68 69 cbc, err := subtle.NewAESCBC(key) 70 require.NoError(t, err) 71 72 plaintext, err := cbc.Decrypt(ciphertext) 73 require.NoError(t, err) 74 require.EqualValues(t, plaintext, message, "plaintext doesn't match message") 75 76 ciphertext1, err := cbc.Encrypt(message) 77 require.NoError(t, err) 78 79 plaintext2, err := cbc.Decrypt(ciphertext1) 80 require.NoError(t, err) 81 require.EqualValues(t, plaintext2, message, "encrypted plaintext doesn't match message") 82 } 83 84 func Test1PUAppendixBExample(t *testing.T) { 85 aad := []byte{ 86 123, 34, 97, 108, 103, 34, 58, 34, 69, 67, 68, 72, 45, 49, 80, 85, 87 43, 65, 49, 50, 56, 75, 87, 34, 44, 34, 101, 110, 99, 34, 58, 34, 88 65, 50, 53, 54, 67, 66, 67, 45, 72, 83, 53, 49, 50, 34, 44, 34, 97, 89 112, 117, 34, 58, 34, 81, 87, 120, 112, 89, 50, 85, 34, 44, 34, 97, 90 112, 118, 34, 58, 34, 81, 109, 57, 105, 73, 71, 70, 117, 90, 67, 66, 91 68, 97, 71, 70, 121, 98, 71, 108, 108, 34, 44, 34, 101, 112, 107, 92 34, 58, 123, 34, 107, 116, 121, 34, 58, 34, 79, 75, 80, 34, 44, 34, 93 99, 114, 118, 34, 58, 34, 88, 50, 53, 53, 49, 57, 34, 44, 34, 120, 94 34, 58, 34, 107, 57, 111, 102, 95, 99, 112, 65, 97, 106, 121, 48, 95 112, 111, 87, 53, 103, 97, 105, 120, 88, 71, 115, 57, 110, 72, 107, 96 119, 103, 49, 65, 70, 113, 85, 65, 70, 97, 51, 57, 100, 121, 66, 99, 97 34, 125, 125, 98 } 99 100 cek := []byte{ 101 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0, 102 0xef, 0xee, 0xed, 0xec, 0xeb, 0xea, 0xe9, 0xe8, 0xe7, 0xe6, 0xe5, 0xe4, 0xe3, 0xe2, 0xe1, 0xe0, 103 0xdf, 0xde, 0xdd, 0xdc, 0xdb, 0xda, 0xd9, 0xd8, 0xd7, 0xd6, 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xd0, 104 0xcf, 0xce, 0xcd, 0xcc, 0xcb, 0xca, 0xc9, 0xc8, 0xc7, 0xc6, 0xc5, 0xc4, 0xc3, 0xc2, 0xc1, 0xc0, 105 } 106 107 iv := []byte{ 108 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 109 } 110 111 aadB64fromAAD := base64.RawURLEncoding.EncodeToString(aad) 112 aadB64 := "eyJhbGciOiJFQ0RILTFQVStBMTI4S1ciLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwiYXB1IjoiUVd4cFkyVSIsImFwdiI6IlFtOWlJ" + 113 "R0Z1WkNCRGFHRnliR2xsIiwiZXBrIjp7Imt0eSI6Ik9LUCIsImNydiI6IlgyNTUxOSIsIngiOiJrOW9mX2NwQWFqeTBwb1c1Z2FpeFhHczlu" + 114 "SGt3ZzFBRnFVQUZhMzlkeUJjIn19" 115 require.Equal(t, aadB64, aadB64fromAAD) 116 117 ivB64 := "AAECAwQFBgcICQoLDA0ODw" 118 ctB64 := "Az2IWsISEMDJvyc5XRL-3-d-RgNBOGolCsxFFoUXFYw" 119 tagB64 := "HLb4fTlm8spGmij3RyOs2gJ4DpHM4hhVRwdF_hGb3WQ" 120 121 plaintext := []byte("Three is a magic number.") 122 123 cbcHMAC, err := josecipher.NewCBCHMAC(cek, aes.NewCipher) 124 require.NoError(t, err) 125 126 cbc := mockNONCEInCBCHMAC{ 127 nonce: iv, 128 cbcHMAC: cbcHMAC, 129 } 130 131 enc, err := cbc.Encrypt(plaintext, []byte(aadB64)) 132 require.NoError(t, err) 133 require.EqualValues(t, iv, enc[:16]) 134 require.Equal(t, ivB64, base64.RawURLEncoding.EncodeToString(enc[:16])) 135 require.Equal(t, ctB64, base64.RawURLEncoding.EncodeToString(enc[16:len(enc)-32])) 136 require.Equal(t, tagB64, base64.RawURLEncoding.EncodeToString(enc[len(enc)-32:])) 137 138 t.Logf("enc: %v", enc) 139 t.Logf("iv: %v", enc[:16]) 140 t.Logf("iv b64: %v", base64.RawURLEncoding.EncodeToString(enc[:16])) 141 t.Logf("ct: %v", enc[16:len(enc)-32]) 142 t.Logf("ct b64: %v", base64.RawURLEncoding.EncodeToString(enc[16:len(enc)-32])) 143 t.Logf("tag: %v", enc[len(enc)-32:]) 144 t.Logf("tag b64: %v", base64.RawURLEncoding.EncodeToString(enc[len(enc)-32:])) 145 t.Logf("aad: %v", aad) 146 t.Logf("aad b64: %v", []byte(aadB64)) 147 t.Logf("aad b64 as string: %v", aadB64) 148 149 dec, err := cbc.Decrypt(enc, []byte(aadB64)) 150 require.NoError(t, err) 151 require.EqualValues(t, plaintext, dec) 152 } 153 154 func TestMultipleEncrypt(t *testing.T) { 155 key := random.GetRandomBytes(16) 156 157 cbc, err := subtle.NewAESCBC(key) 158 require.NoError(t, err) 159 160 plaintext := []byte("Some data to encrypt.") 161 ciphertext1, err := cbc.Encrypt(plaintext) 162 require.NoError(t, err) 163 164 ciphertext2, err := cbc.Encrypt(plaintext) 165 require.NoError(t, err) 166 require.NotEqualValues(t, ciphertext1, ciphertext2, "the two ciphertexts cannot be equal") 167 168 // Encrypt 100 times and verify that the result is 100 different ciphertexts. 169 ciphertexts := map[string]bool{} 170 171 for i := 0; i < 100; i++ { 172 c, err := cbc.Encrypt(plaintext) 173 require.NoErrorf(t, err, fmt.Sprintf("encryption failed for iteration %d, error: %v", i, err)) 174 175 ciphertexts[string(c)] = true 176 } 177 178 require.Equal(t, 100, len(ciphertexts)) 179 } 180 181 func TestEncryptDecrypt(t *testing.T) { 182 key, err := hex.DecodeString("000102030405060708090a0b0c0d0e0f") 183 require.NoError(t, err) 184 185 cbc, err := subtle.NewAESCBC(key) 186 require.NoError(t, err) 187 188 message := []byte("Some data to encrypt.") 189 ciphertext, err := cbc.Encrypt(message) 190 require.NoError(t, err) 191 192 validateCiphertext(t, message, ciphertext, -1) 193 194 plaintext, err := cbc.Decrypt(ciphertext) 195 require.NoError(t, err) 196 require.EqualValues(t, message, plaintext) 197 198 t.Run("failure - decrypt short ciphertext", func(t *testing.T) { 199 _, err = cbc.Decrypt([]byte("short ct")) 200 require.EqualError(t, err, "aes_cbc: ciphertext too short") 201 }) 202 203 t.Run("failure - decrypt ciphertext not bloc multiple", func(t *testing.T) { 204 _, err = cbc.Decrypt([]byte("short ciphertext not multiple")) 205 require.EqualError(t, err, "aes_cbc: invalid ciphertext padding") 206 }) 207 } 208 209 func TestFailEncryptDecrypt(t *testing.T) { 210 t.Run("failure - encrypt failing with invalid key size", func(t *testing.T) { 211 key, err := hex.DecodeString("000102030405060708090a0b0c0d0e0f") 212 require.NoError(t, err) 213 214 cbc, err := subtle.NewAESCBC(key) 215 require.NoError(t, err) 216 217 // set invalid key size 218 cbc.Key = []byte("bad key Size") 219 220 _, err = cbc.Encrypt([]byte("plaintext")) 221 require.EqualError(t, err, "aes_cbc: Encrypt() aes_cbc: failed to create block cipher, error: crypto/aes: "+ 222 "invalid key size 12") 223 224 _, err = cbc.Decrypt([]byte("ciphertext bloc size")) 225 require.EqualError(t, err, "aes_cbc: Decrypt() aes_cbc: failed to create block cipher, error: crypto/aes:"+ 226 " invalid key size 12") 227 }) 228 } 229 230 func TestEncryptRandomMessage(t *testing.T) { 231 key := random.GetRandomBytes(16) 232 233 cbc, err := subtle.NewAESCBC(key) 234 require.NoError(t, err) 235 236 for i := 0; i < 256; i++ { 237 message := random.GetRandomBytes(uint32(i)) 238 ciphertext, err := cbc.Encrypt(message) 239 require.NoError(t, err) 240 241 validateCiphertext(t, message, ciphertext, i) 242 243 plaintext, err := cbc.Decrypt(ciphertext) 244 require.NoError(t, err, fmt.Sprintf("decryption failed at iteration %d, error: %v", i, err)) 245 require.EqualValuesf(t, message, plaintext, fmt.Sprintf("plaintext doesn't match message, i = %d", i)) 246 } 247 } 248 249 func TestEncryptRandomKeyAndMessage(t *testing.T) { 250 for i := 0; i < 256; i++ { 251 key := random.GetRandomBytes(16) 252 253 cbc, err := subtle.NewAESCBC(key) 254 require.NoError(t, err) 255 256 message := random.GetRandomBytes(uint32(i)) 257 258 ciphertext, err := cbc.Encrypt(message) 259 require.NoErrorf(t, err, "encryption failed at iteration %d", i) 260 261 validateCiphertext(t, message, ciphertext, i) 262 263 plaintext, err := cbc.Decrypt(ciphertext) 264 require.NoError(t, err, fmt.Sprintf("decryption failed at iteration %d, error: %v", i, err)) 265 require.EqualValuesf(t, message, plaintext, fmt.Sprintf("plaintext doesn't match message, i = %d", i)) 266 } 267 } 268 269 func validateCiphertext(t *testing.T, plaintext, ciphertext []byte, id int) { 270 t.Helper() 271 272 padding := aes.BlockSize - ((len(plaintext) + subtle.AESCBCIVSize) % aes.BlockSize) 273 expectedCTSize := len(plaintext) + subtle.AESCBCIVSize + padding 274 require.Equalf(t, len(ciphertext), expectedCTSize, fmt.Sprintf("invalid ciphertext length for i = %d, "+ 275 "ciphertext length: %d, msg length: %d", id, len(ciphertext), len(plaintext)+subtle.AESCBCIVSize)) 276 } 277 278 func TestPadUnpad(t *testing.T) { 279 // test pad empty text. 280 ciphertext := []byte("") 281 paddedCT := subtle.Pad(ciphertext, 0, aes.BlockSize) 282 unpaddedCT := subtle.Unpad(paddedCT) 283 require.EqualValues(t, ciphertext, unpaddedCT) 284 285 newCiphertext := append(ciphertext, byte(0)) 286 for i := 1; i < 3*aes.BlockSize+1; i++ { 287 paddedCT = subtle.Pad(newCiphertext, len(newCiphertext), aes.BlockSize) 288 unpaddedCT = subtle.Unpad(paddedCT) 289 require.EqualValues(t, newCiphertext, unpaddedCT) 290 291 newCiphertext = append(newCiphertext, byte(i)) 292 } 293 }