-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #29 from Bit-Nation/feature/aes_ctr
AES CTR
- Loading branch information
Showing
20 changed files
with
1,094 additions
and
274 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package aes | ||
|
||
import ( | ||
"crypto/aes" | ||
"crypto/cipher" | ||
"crypto/rand" | ||
"io" | ||
) | ||
|
||
var cfbRandReader io.Reader = rand.Reader | ||
|
||
// encrypt a plain text with given secret | ||
// Deprecated: use CTREncrypt instead | ||
func CFBEncrypt(plainText PlainText, key Secret) (CipherText, error) { | ||
|
||
// create block | ||
block, err := aes.NewCipher(key[:]) | ||
if err != nil { | ||
return CipherText{}, err | ||
} | ||
|
||
// create IV | ||
iv := make([]byte, aes.BlockSize) | ||
if _, err := io.ReadFull(cfbRandReader, iv); err != nil { | ||
return CipherText{}, err | ||
} | ||
|
||
// create cfb encrypter | ||
stream := cipher.NewCFBEncrypter(block, iv) | ||
cipherText := make([]byte, len(plainText)) | ||
stream.XORKeyStream(cipherText, plainText) | ||
|
||
// cipher text | ||
ct := CipherText{ | ||
IV: iv, | ||
CipherText: cipherText, | ||
Version: 1, | ||
} | ||
|
||
// create mac | ||
mac, err := vOneMac(ct, key) | ||
if err != nil { | ||
return CipherText{}, err | ||
} | ||
ct.Mac = mac | ||
|
||
return ct, nil | ||
|
||
} | ||
|
||
// decrypt a cipher text with given secret | ||
// Deprecated: use CFBDecrypt instead | ||
func CFBDecrypt(cipherText CipherText, key Secret) (PlainText, error) { | ||
|
||
// create block | ||
block, err := aes.NewCipher(key[:]) | ||
if err != nil { | ||
return PlainText{}, err | ||
} | ||
|
||
valid, err := cipherText.ValidMAC(key) | ||
if err != nil { | ||
return PlainText{}, err | ||
} | ||
if !valid { | ||
return PlainText{}, MacError | ||
} | ||
|
||
stream := cipher.NewCFBDecrypter(block, cipherText.IV) | ||
|
||
cc := cipherText.CipherText | ||
|
||
// XORKeyStream can work in-place if the two arguments are the same. | ||
stream.XORKeyStream(cc, cc) | ||
|
||
return cc, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,183 @@ | ||
package aes | ||
|
||
import ( | ||
"bytes" | ||
"encoding/hex" | ||
"testing" | ||
|
||
require "github.com/stretchr/testify/require" | ||
) | ||
|
||
// Test the encrypt and decrypt function in one batch | ||
func CFBTestSuccessEncryptDecrypt(t *testing.T) { | ||
|
||
secret := Secret{ | ||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
} | ||
value := []byte("I am the value") | ||
|
||
//Encrypt | ||
cipherText, e := CFBEncrypt(value, secret) | ||
require.Nil(t, e) | ||
|
||
//Decrypt | ||
res, err := CFBDecrypt(cipherText, secret) | ||
require.Nil(t, err) | ||
|
||
//Decrypted value must match the given value | ||
require.Equal(t, string(value), string(res)) | ||
|
||
} | ||
|
||
func CFBTestFailedDecryption(t *testing.T) { | ||
|
||
secret := Secret{ | ||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
} | ||
value := []byte("I am the plain text") | ||
|
||
// encrypt | ||
cipherText, e := CFBEncrypt(value, secret) | ||
require.Nil(t, e) | ||
|
||
// change last byte to fail on decryption | ||
secret[31] = 0x01 | ||
|
||
// decrypt | ||
plainText, err := CFBDecrypt(cipherText, secret) | ||
require.Equal(t, PlainText{}, plainText) | ||
require.EqualError(t, err, "invalid key - message authentication failed") | ||
|
||
} | ||
|
||
func TestCFBEncrypt(t *testing.T) { | ||
|
||
// encryption key | ||
encryptionKey, err := hex.DecodeString("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4") | ||
require.Nil(t, err) | ||
|
||
// aes cfb test vectors | ||
testVectors := []testVector{ | ||
testVector{ | ||
iv: "000102030405060708090a0b0c0d0e0f", | ||
plainText: "6bc1bee22e409f96e93d7e117393172a", | ||
cipherText: "dc7e84bfda79164b7ecd8486985d3860", | ||
}, | ||
testVector{ | ||
iv: "dc7e84bfda79164b7ecd8486985d3860", | ||
plainText: "ae2d8a571e03ac9c9eb76fac45af8e51", | ||
cipherText: "39ffed143b28b1c832113c6331e5407b", | ||
}, | ||
testVector{ | ||
iv: "39ffed143b28b1c832113c6331e5407b", | ||
plainText: "30c81c46a35ce411e5fbc1191a0a52ef", | ||
cipherText: "df10132415e54b92a13ed0a8267ae2f9", | ||
}, | ||
testVector{ | ||
iv: "df10132415e54b92a13ed0a8267ae2f9", | ||
plainText: "f69f2445df4f9b17ad2b417be66c3710", | ||
cipherText: "75a385741ab9cef82031623d55b1e471", | ||
}, | ||
} | ||
|
||
for _, v := range testVectors { | ||
|
||
// initialisation vector | ||
iv, err := hex.DecodeString(v.iv) | ||
require.Nil(t, err) | ||
cfbRandReader = bytes.NewReader(iv) | ||
|
||
// plain text | ||
plainText, err := hex.DecodeString(v.plainText) | ||
require.Nil(t, err) | ||
|
||
// cipher text | ||
cipherText, err := hex.DecodeString(v.cipherText) | ||
require.Nil(t, err) | ||
// create secret key | ||
secKey := Secret{} | ||
copy(secKey[:], encryptionKey) | ||
|
||
// encrypt | ||
ct, err := CFBEncrypt(plainText, secKey) | ||
require.Nil(t, err) | ||
|
||
require.Equal(t, hex.EncodeToString(cipherText), hex.EncodeToString(ct.CipherText)) | ||
|
||
} | ||
|
||
} | ||
|
||
func TestCFBDecrypt(t *testing.T) { | ||
|
||
// encryption key | ||
encryptionKey, err := hex.DecodeString("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4") | ||
require.Nil(t, err) | ||
|
||
// aes cfb test vectors | ||
testVectors := []testVector{ | ||
testVector{ | ||
iv: "000102030405060708090a0b0c0d0e0f", | ||
plainText: "6bc1bee22e409f96e93d7e117393172a", | ||
cipherText: "dc7e84bfda79164b7ecd8486985d3860", | ||
mac: "43517b9531fdb8565ce2a6af1cbb24930cb7ec2b3685701cfac6731bb861cb60", | ||
}, | ||
testVector{ | ||
iv: "dc7e84bfda79164b7ecd8486985d3860", | ||
plainText: "ae2d8a571e03ac9c9eb76fac45af8e51", | ||
cipherText: "39ffed143b28b1c832113c6331e5407b", | ||
mac: "de571950b74a72055810fad70421676aeadd651d6bd3ba6ad0348a7c7c9ebc8e", | ||
}, | ||
testVector{ | ||
iv: "39ffed143b28b1c832113c6331e5407b", | ||
plainText: "30c81c46a35ce411e5fbc1191a0a52ef", | ||
cipherText: "df10132415e54b92a13ed0a8267ae2f9", | ||
mac: "6ce26e57380b71dec45177dda9d1d322e1dceba40b462b6c15990a43bb1b2ec2", | ||
}, | ||
testVector{ | ||
iv: "df10132415e54b92a13ed0a8267ae2f9", | ||
plainText: "f69f2445df4f9b17ad2b417be66c3710", | ||
cipherText: "75a385741ab9cef82031623d55b1e471", | ||
mac: "73fb351bba3a8299d2271ff489dc4ed2412e69653b9877bc19a6b408c51e83da", | ||
}, | ||
} | ||
|
||
for _, v := range testVectors { | ||
|
||
// initialisation vector | ||
iv, err := hex.DecodeString(v.iv) | ||
require.Nil(t, err) | ||
cfbRandReader = bytes.NewReader(iv) | ||
|
||
// mac | ||
mac, err := hex.DecodeString(v.mac) | ||
require.Nil(t, err) | ||
|
||
// cipher text | ||
cipherText, err := hex.DecodeString(v.cipherText) | ||
require.Nil(t, err) | ||
|
||
// create secret key | ||
secKey := Secret{} | ||
copy(secKey[:], encryptionKey) | ||
|
||
// encrypt | ||
plain, err := CFBDecrypt(CipherText{ | ||
IV: iv, | ||
Mac: mac, | ||
CipherText: cipherText, | ||
Version: uint8(1), | ||
}, secKey) | ||
require.Nil(t, err) | ||
|
||
require.Equal(t, v.plainText, hex.EncodeToString(plain)) | ||
|
||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
package aes | ||
|
||
import ( | ||
"crypto/aes" | ||
"crypto/cipher" | ||
"crypto/rand" | ||
"io" | ||
) | ||
|
||
var ctrRandReader io.Reader = rand.Reader | ||
|
||
// encrypt plain text by given key using AES CTR 256 | ||
func CTREncrypt(plainText PlainText, secret Secret) (CipherText, error) { | ||
|
||
// block | ||
block, err := aes.NewCipher(secret[:]) | ||
if err != nil { | ||
return CipherText{}, err | ||
} | ||
|
||
// initialisation vector | ||
iv := make([]byte, 16) | ||
_, err = io.ReadFull(ctrRandReader, iv) | ||
if err != nil { | ||
return CipherText{}, err | ||
} | ||
|
||
// create cipher text | ||
cipherText := make([]byte, len(plainText)) | ||
|
||
// encrypt | ||
stream := cipher.NewCTR(block, iv) | ||
stream.XORKeyStream(cipherText, plainText) | ||
|
||
// create cipher text | ||
ct := CipherText{ | ||
IV: iv, | ||
CipherText: cipherText, | ||
Version: 2, | ||
} | ||
|
||
// create mac | ||
mac, err := vTwoMac(ct, secret) | ||
ct.Mac = mac | ||
|
||
return ct, err | ||
} | ||
|
||
// decrypt cipher text by given key | ||
func CTRDecrypt(cipherText CipherText, key Secret) (PlainText, error) { | ||
|
||
// create block | ||
block, err := aes.NewCipher(key[:]) | ||
if err != nil { | ||
return PlainText{}, err | ||
} | ||
|
||
// validate key | ||
valid, err := cipherText.ValidMAC(key) | ||
if err != nil { | ||
return PlainText{}, err | ||
} | ||
if !valid { | ||
return PlainText{}, MacError | ||
} | ||
|
||
// decrypt | ||
plainText := make(PlainText, len(cipherText.CipherText)) | ||
stream := cipher.NewCTR(block, cipherText.IV) | ||
stream.XORKeyStream(plainText, cipherText.CipherText) | ||
|
||
return plainText, nil | ||
|
||
} |
Oops, something went wrong.