266 lines
5.8 KiB
Go
266 lines
5.8 KiB
Go
package blockmode_test
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"testing"
|
|
"time"
|
|
|
|
"xdx.jelly/xgcl/grand"
|
|
"xdx.jelly/xgcl/sm/sm4"
|
|
"xdx.jelly/xgcl/utils/blockmode"
|
|
)
|
|
|
|
// sm4_GCM模式
|
|
var sm4GCMTests = []struct {
|
|
key, nonce, plaintext, ad, result string
|
|
}{
|
|
{
|
|
"11754cd72aec309bf52f7687212e8957",
|
|
"3c819d9a9bed087615030b65", // nonce should be 12 bytes.
|
|
"plaintext",
|
|
"additional message not need encrypt, empty is ok",
|
|
"6111f78f2f82b913c20e333160bfec034c3720ac133a6203b1",
|
|
},
|
|
}
|
|
|
|
func TestSM4Speed(t *testing.T) {
|
|
key, err := hex.DecodeString("12345678123456781234567812345678")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
block, err := sm4.NewCipher(key)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
gcm, err := blockmode.NewGCM(blockmode.Wrap(block))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
nonce, err := hex.DecodeString("123456781234567812345678")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
plaintext := grand.GetRandom(1024 * 1024)
|
|
ad := []byte("additional message not need encrypt, empty is ok")
|
|
ct2 := make([]byte, 0, 1024*1024+gcm.Overhead())
|
|
cnt := 100
|
|
start := time.Now()
|
|
for i := 0; i < cnt; i++ {
|
|
err = gcm.EncryptInit(nonce)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
gcm.SpecifyADD(ad)
|
|
ct2, err := gcm.EncryptUpdate(ct2, plaintext)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
ct2, err = gcm.EncryptFinal(ct2)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
end := time.Now()
|
|
elapsed := end.Sub(start)
|
|
fmt.Printf("%f Bps\n", float64(len(plaintext)*cnt)/1024/1024*1000/float64(elapsed.Milliseconds()))
|
|
|
|
}
|
|
|
|
func TestSM4GCM(t *testing.T) {
|
|
for i, test := range sm4GCMTests {
|
|
key, _ := hex.DecodeString(test.key)
|
|
|
|
block, _ := sm4.NewCipher(key)
|
|
gcm, err := blockmode.NewGCM(blockmode.Wrap(block))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
nonce, _ := hex.DecodeString(test.nonce)
|
|
plaintext := []byte(test.plaintext)
|
|
|
|
ad := []byte(test.ad)
|
|
|
|
// 提前分配好空间
|
|
for i := 0; i < gcm.Overhead(); i++ {
|
|
plaintext = append(plaintext, 0)
|
|
}
|
|
plaintext = plaintext[:len(plaintext)-gcm.Overhead()]
|
|
|
|
ct := gcm.Seal(plaintext[:0], nonce, plaintext, ad)
|
|
|
|
if ctHex := hex.EncodeToString(ct); ctHex != test.result {
|
|
t.Errorf("#%d: got %s, want %s", i, ctHex, test.result)
|
|
continue
|
|
}
|
|
|
|
plaintext, err = gcm.Open(ct[:0], nonce, ct, ad)
|
|
if err != nil {
|
|
t.Errorf("#%d: Open failed", i)
|
|
continue
|
|
}
|
|
|
|
if !bytes.Equal(plaintext, []byte(test.plaintext)) {
|
|
t.Errorf("#%d: plaintext's don't match: got %x vs %x", i, test.plaintext, plaintext)
|
|
continue
|
|
}
|
|
|
|
// if ad, nonce, ct was changed, return err
|
|
if len(ad) > 0 {
|
|
ad[0] ^= 0x80
|
|
if _, err := gcm.Open(nil, nonce, ct, ad); err == nil {
|
|
t.Errorf("#%d: Open was successful after altering additional data", i)
|
|
}
|
|
ad[0] ^= 0x80
|
|
}
|
|
|
|
nonce[0] ^= 0x80
|
|
if _, err := gcm.Open(nil, nonce, ct, ad); err == nil {
|
|
t.Errorf("#%d: Open was successful after altering nonce", i)
|
|
}
|
|
nonce[0] ^= 0x80
|
|
|
|
ct[0] ^= 0x80
|
|
if _, err := gcm.Open(nil, nonce, ct, ad); err == nil {
|
|
t.Errorf("#%d: Open was successful after altering ciphertext", i)
|
|
}
|
|
ct[0] ^= 0x80
|
|
}
|
|
}
|
|
|
|
func TestGcmUpdate(t *testing.T) {
|
|
test := sm4GCMTests[0]
|
|
key, _ := hex.DecodeString(test.key)
|
|
|
|
block, _ := sm4.NewCipher(key)
|
|
gcm, err := blockmode.NewGCM(blockmode.Wrap(block))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
nonce, _ := hex.DecodeString(test.nonce)
|
|
plaintext := grand.GetRandom(0)
|
|
ad := []byte(test.ad)
|
|
ct1 := gcm.Seal(nil, nonce, plaintext, ad)
|
|
|
|
ct2 := make([]byte, 0, 116)
|
|
err = gcm.EncryptInit(nonce)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
gcm.SpecifyADD(ad)
|
|
for i := range plaintext {
|
|
ct2, err = gcm.EncryptUpdate(ct2, []byte{plaintext[i]})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
ct2, err = gcm.EncryptFinal(ct2)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !bytes.Equal(ct1, ct2) {
|
|
t.Errorf("Seal failed")
|
|
}
|
|
|
|
if err = gcm.DecryptInit(nonce); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
gcm.SpecifyADD(ad)
|
|
|
|
decrypted := make([]byte, 0, len(plaintext))
|
|
for i := range ct1 {
|
|
decrypted, err = gcm.DecryptUpdate(decrypted, []byte{ct1[i]})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
decrypted, err = gcm.DecryptFinal(decrypted)
|
|
if !bytes.Equal(decrypted, plaintext) {
|
|
t.Fatal("plaintext unequal decrypted plaintext")
|
|
}
|
|
if err != nil {
|
|
t.Fatal("auth failed")
|
|
}
|
|
}
|
|
|
|
func FuzzSm4Gcm(f *testing.F) {
|
|
nonce := grand.GetRandom(12)
|
|
key := grand.GetRandom(16)
|
|
|
|
block, _ := sm4.NewCipher(key)
|
|
gcm, err := blockmode.NewGCM(blockmode.Wrap(block))
|
|
if err != nil {
|
|
f.Fatal(err)
|
|
}
|
|
stdgcm, _ := sm4.NewGCM(key)
|
|
|
|
f.Add([]byte{}, []byte{})
|
|
f.Fuzz(func(t *testing.T, plaintext, ad []byte) {
|
|
stdct := stdgcm.Seal(nil, nonce, plaintext, ad)
|
|
ct1 := gcm.Seal(nil, nonce, plaintext, ad)
|
|
if !bytes.Equal(ct1, stdct) {
|
|
t.Errorf("Seal failed")
|
|
}
|
|
|
|
if err := gcm.EncryptInit(nonce); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
// if additional data is empty, then call
|
|
// gcm.SpecifyADD(nil)
|
|
gcm.SpecifyADD(ad)
|
|
|
|
ct2, err := gcm.EncryptUpdate(nil, plaintext[:len(plaintext)/2])
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, p := range plaintext[len(plaintext)/2:] {
|
|
if ct2, err = gcm.EncryptUpdate(ct2, []byte{p}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
ct2, err = gcm.EncryptFinal(ct2)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if !bytes.Equal(ct2, stdct) {
|
|
t.Errorf("Encrypt failed")
|
|
}
|
|
|
|
pt1, err1 := gcm.Open(nil, nonce, ct1, ad)
|
|
if err1 != nil {
|
|
t.Errorf("Open faile: %v\n", err1)
|
|
}
|
|
if err := gcm.DecryptInit(nonce); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
gcm.SpecifyADD(ad)
|
|
|
|
pt2, err := gcm.DecryptUpdate(nil, ct2[:len(ct2)/2])
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, p := range ct2[len(ct2)/2:] {
|
|
if pt2, err = gcm.DecryptUpdate(pt2, []byte{p}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
pt2, err = gcm.DecryptFinal(pt2)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !bytes.Equal(pt2, plaintext) {
|
|
t.Errorf("Decrypt failed")
|
|
}
|
|
|
|
if !bytes.Equal(pt1, plaintext) {
|
|
t.Errorf("Open failed")
|
|
}
|
|
})
|
|
}
|