| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| package aead_test |
| |
| import ( |
| "bytes" |
| "crypto/aes" |
| "encoding/hex" |
| "strings" |
| "testing" |
| |
| "github.com/google/tink/go/subtle/aead" |
| "github.com/google/tink/go/subtle/random" |
| ) |
| |
| func TestNewAESCTR(t *testing.T) { |
| key := make([]byte, 64) |
| |
| // Test various key sizes with a fixed IV size. |
| for i := 0; i < 64; i++ { |
| k := key[:i] |
| c, err := aead.NewAESCTR(k, aead.AESCTRMinIVSize) |
| |
| switch len(k) { |
| case 16: |
| fallthrough |
| case 32: |
| // Valid key sizes. |
| if err != nil { |
| t.Errorf("want: valid cipher (key size=%d), got: error %v", len(k), err) |
| } |
| // Verify that the struct contents are correctly set. |
| if len(c.Key) != len(k) { |
| t.Errorf("want: key size=%d, got: key size=%d", len(k), len(c.Key)) |
| } |
| if c.IVSize != aead.AESCTRMinIVSize { |
| t.Errorf("want: IV size=%d, got: IV size=%d", aead.AESCTRMinIVSize, c.IVSize) |
| } |
| default: |
| // Invalid key sizes. |
| if !strings.Contains(err.Error(), "aes_ctr: invalid AES key size; want 16 or 32") { |
| t.Errorf("wrong error message; want a string starting with \"aes_ctr: invalid AES key size; want 16 or 32\", got %v", err) |
| } |
| } |
| } |
| |
| // Test different IV sizes with a fixed key. |
| for i := 0; i < 64; i++ { |
| k := key[:16] |
| c, err := aead.NewAESCTR(k, i) |
| if i >= aead.AESCTRMinIVSize && i <= aes.BlockSize { |
| if err != nil { |
| t.Errorf("want: valid cipher (IV size=%d), got: error %v", i, err) |
| } |
| if len(c.Key) != len(k) { |
| t.Errorf("want: key size=%d, got: key size=%d", len(k), len(c.Key)) |
| } |
| if c.IVSize != i { |
| t.Errorf("want: IV size=%d, got: IV size=%d", i, c.IVSize) |
| } |
| continue |
| } |
| if !strings.Contains(err.Error(), "aes_ctr: invalid IV size:") { |
| t.Errorf("want: error invalid IV size, got: %v", err) |
| } |
| } |
| } |
| |
| func TestNistTestVector(t *testing.T) { |
| // NIST SP 800-38A pp 55 |
| key, err := hex.DecodeString("2b7e151628aed2a6abf7158809cf4f3c") |
| if err != nil { |
| t.Fatalf("failed to hex decode key, error: %v", err) |
| } |
| |
| // NIST IV |
| iv := "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff" |
| // NIST ciphertext blocks |
| c := "874d6191b620e3261bef6864990db6ce" + |
| "9806f66b7970fdff8617187bb9fffdff" + |
| "5ae4df3edbd5d35e5b4f09020db03eab" + |
| "1e031dda2fbe03d1792170a0f3009cee" |
| ciphertext, err := hex.DecodeString(iv + c) |
| if err != nil { |
| t.Fatalf("failed to hex decode ciphertext, error: %v", err) |
| } |
| |
| // NIST plaintext blocks |
| p := "6bc1bee22e409f96e93d7e117393172a" + |
| "ae2d8a571e03ac9c9eb76fac45af8e51" + |
| "30c81c46a35ce411e5fbc1191a0a52ef" + |
| "f69f2445df4f9b17ad2b417be66c3710" |
| message, err := hex.DecodeString(p) |
| if err != nil { |
| t.Fatalf("failed to hex decode message, error: %v", err) |
| } |
| |
| stream, err := aead.NewAESCTR(key, len(iv)/2) |
| if err != nil { |
| t.Fatalf("failed to create AESCTR instance, error: %v", err) |
| } |
| |
| plaintext, err := stream.Decrypt(ciphertext) |
| if err != nil { |
| t.Errorf("failed to decrypt ciphertext, error: %v", err) |
| } |
| |
| if !bytes.Equal(plaintext, message) { |
| t.Errorf("plaintext doesn't match message") |
| } |
| } |
| |
| func TestMultipleEncrypt(t *testing.T) { |
| key := random.GetRandomBytes(16) |
| |
| stream, err := aead.NewAESCTR(key, aead.AESCTRMinIVSize) |
| if err != nil { |
| t.Fatalf("failed to create AESCTR instance, error: %v", err) |
| } |
| |
| plaintext := []byte("Some data to encrypt.") |
| ct1, err := stream.Encrypt(plaintext) |
| if err != nil { |
| t.Errorf("encryption failed, error: %v", err) |
| } |
| ct2, err := stream.Encrypt(plaintext) |
| if err != nil { |
| t.Errorf("encryption failed, error: %v", err) |
| } |
| if bytes.Equal(ct1, ct2) { |
| t.Error("the two ciphertexts cannot be equal") |
| } |
| // Encrypt 100 times and verify that the result is 100 different ciphertexts. |
| ciphertexts := map[string]bool{} |
| for i := 0; i < 100; i++ { |
| c, err := stream.Encrypt(plaintext) |
| if err != nil { |
| t.Errorf("encryption failed for iteration %d, error: %v", i, err) |
| } |
| ciphertexts[string(c)] = true |
| } |
| |
| if len(ciphertexts) != 100 { |
| t.Errorf("got: %d ciphertexts, want: 100 ciphertexts", len(ciphertexts)) |
| } |
| } |
| |
| func TestEncryptDecrypt(t *testing.T) { |
| key, err := hex.DecodeString("000102030405060708090a0b0c0d0e0f") |
| if err != nil { |
| t.Fatal("failed to hex decode key") |
| } |
| |
| stream, err := aead.NewAESCTR(key, aead.AESCTRMinIVSize) |
| if err != nil { |
| t.Fatalf("failed to get AESCTR instance, error: %v", err) |
| } |
| |
| message := []byte("Some data to encrypt.") |
| ciphertext, err := stream.Encrypt(message) |
| if err != nil { |
| t.Errorf("encryption failed, error: %v", err) |
| } |
| |
| if len(ciphertext) != len(message)+aead.AESCTRMinIVSize { |
| t.Errorf("ciphertext incorrect size, got: %d, want: %d", len(ciphertext), len(message)+aead.AESCTRMinIVSize) |
| } |
| |
| plaintext, err := stream.Decrypt(ciphertext) |
| if err != nil { |
| t.Errorf("decryption failed, error: %v", err) |
| } |
| |
| if !bytes.Equal(message, plaintext) { |
| t.Errorf("decryption result mismatch, got: %v, want: %v", plaintext, message) |
| } |
| } |
| |
| func TestEncryptRandomMessage(t *testing.T) { |
| key := random.GetRandomBytes(16) |
| |
| stream, err := aead.NewAESCTR(key, aead.AESCTRMinIVSize) |
| if err != nil { |
| t.Errorf("failed to instantiate AESCTR, error: %v", err) |
| } |
| |
| for i := 0; i < 256; i++ { |
| message := random.GetRandomBytes(uint32(i)) |
| ciphertext, err := stream.Encrypt(message) |
| if err != nil { |
| t.Errorf("encryption failed at iteration %d, error: %v", i, err) |
| } |
| if len(ciphertext) != len(message)+aead.AESCTRMinIVSize { |
| t.Errorf("invalid ciphertext length for i = %d", i) |
| } |
| |
| plaintext, err := stream.Decrypt(ciphertext) |
| if err != nil { |
| t.Errorf("decryption failed at iteration %d, error: %v", i, err) |
| } |
| |
| if !bytes.Equal(plaintext, message) { |
| t.Errorf("plaintext doesn't match message, i = %d", i) |
| } |
| } |
| } |
| |
| func TestEncryptRandomKeyAndMessage(t *testing.T) { |
| for i := 0; i < 256; i++ { |
| key := random.GetRandomBytes(16) |
| |
| stream, err := aead.NewAESCTR(key, aead.AESCTRMinIVSize) |
| if err != nil { |
| t.Errorf("failed to instantiate AESCTR, error: %v", err) |
| } |
| |
| message := random.GetRandomBytes(uint32(i)) |
| ciphertext, err := stream.Encrypt(message) |
| if err != nil { |
| t.Errorf("encryption failed at iteration %d, error: %v", i, err) |
| } |
| if len(ciphertext) != len(message)+aead.AESCTRMinIVSize { |
| t.Errorf("invalid ciphertext length for i = %d", i) |
| } |
| |
| plaintext, err := stream.Decrypt(ciphertext) |
| if err != nil { |
| t.Errorf("decryption failed at iteration %d, error: %v", i, err) |
| } |
| |
| if !bytes.Equal(plaintext, message) { |
| t.Errorf("plaintext doesn't match message, i = %d", i) |
| } |
| } |
| } |