blob: ecfce7dca4985516273d6e7666481c35f87e61b7 [file] [log] [blame]
// 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)
}
}
}