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  }