add example test for sm3 sm4 pkcs8

This commit is contained in:
Sun Yimin 2023-02-02 11:45:57 +08:00 committed by GitHub
parent 5b806c85fe
commit a2d54159ad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 398 additions and 16 deletions

View File

@ -9,6 +9,8 @@ import (
"github.com/emmansun/gmsm/pkcs8"
"github.com/emmansun/gmsm/sm2"
"github.com/emmansun/gmsm/sm9"
"golang.org/x/crypto/cryptobyte"
)
func ExampleMarshalPrivateKey_withoutPassword() {
@ -224,3 +226,55 @@ jZHNffmk4ii7NxCfjrzpiFq4clYsNMXeSEnq1tuOEur4kYcjHYSIFc9bPG656a60
}
// Output: ok
}
func ExampleMarshalPrivateKey_withoutPasswordSM9MasterSignKey() {
// real private key should be from secret storage, or generate directly
kb, _ := hex.DecodeString("0130E78459D78545CB54C587E02CF480CE0B66340F319F348A1D5B1F2DC5F4")
var b cryptobyte.Builder
b.AddASN1BigInt(new(big.Int).SetBytes(kb))
kb, _ = b.Bytes()
testkey := new(sm9.SignMasterPrivateKey)
err := testkey.UnmarshalASN1(kb)
if err != nil {
panic(err)
}
// generate der bytes
der, err := pkcs8.MarshalPrivateKey(testkey, nil, nil)
if err != nil {
fmt.Fprintf(os.Stderr, "Error from MarshalPrivateKey: %s\n", err)
return
}
// encode der bytes to pem
block := &pem.Block{Bytes: der, Type: "SM9 SIGN PRIVATE KEY"}
pemContent := string(pem.EncodeToMemory(block))
fmt.Printf("%v\n", pemContent)
}
func ExampleParseSM9SignMasterPrivateKey_withoutPassword() {
const privateKeyPem = `
-----BEGIN SM9 SIGN PRIVATE KEY-----
MIHGAgEAMBUGCCqBHM9VAYIuBgkqgRzPVQGCLgEEgakwgaYCHwEw54RZ14VFy1TF
h+As9IDOC2Y0DzGfNIodWx8txfQDgYIABJ9kCAswhPcz5Ir/S0G1ZQEc4HEcXjks
+wqxtnkblMQIKduhFhUtH3hs6EPtJKO1c0FNIXc4apLdjxTWVpbqXjJphQk4q+oB
ErVzKfRH46DLrT4v2xp38zXonhQI0O8cJUHgClPdpTLaGnzgJ7ekb3QQBuhfXN/w
cw51wF+04yFt
-----END SM9 SIGN PRIVATE KEY-----`
block, _ := pem.Decode([]byte(privateKeyPem))
if block == nil {
fmt.Fprintf(os.Stderr, "Failed to parse PEM block\n")
return
}
pk, err := pkcs8.ParseSM9SignMasterPrivateKey(block.Bytes)
if err != nil {
fmt.Fprintf(os.Stderr, "Error from ParseSM9SignMasterPrivateKey: %s\n", err)
return
}
if pk != nil {
fmt.Println("ok")
} else {
fmt.Println("fail")
}
// Output: ok
}

38
sm3/example_test.go Normal file
View File

@ -0,0 +1,38 @@
package sm3_test
import (
"fmt"
"io"
"log"
"os"
"github.com/emmansun/gmsm/sm3"
)
func ExampleSum() {
sum := sm3.Sum([]byte("hello world\n"))
fmt.Printf("%x", sum)
// Output: 4cc2036b86431b5d2685a04d289dfe140a36baa854b01cb39fcd6009638e4e7a
}
func ExampleNew() {
h := sm3.New()
h.Write([]byte("hello world\n"))
fmt.Printf("%x", h.Sum(nil))
// Output: 4cc2036b86431b5d2685a04d289dfe140a36baa854b01cb39fcd6009638e4e7a
}
func ExampleNew_file() {
f, err := os.Open("file.txt")
if err != nil {
log.Fatal(err)
}
defer f.Close()
h := sm3.New()
if _, err := io.Copy(h, f); err != nil {
log.Fatal(err)
}
fmt.Printf("%x", h.Sum(nil))
}

View File

@ -1,12 +1,15 @@
package sm4_test
import (
"bytes"
"crypto/cipher"
"crypto/rand"
"encoding/hex"
"fmt"
"io"
"os"
smcipher "github.com/emmansun/gmsm/cipher"
"github.com/emmansun/gmsm/padding"
"github.com/emmansun/gmsm/sm4"
)
@ -138,3 +141,268 @@ func Example_decryptGCM() {
fmt.Printf("%s\n", plaintext)
// Output: exampleplaintext
}
func Example_encryptCCM() {
// Load your secret key from a safe place and reuse it across multiple
// Seal/Open calls. (Obviously don't use this example key for anything
// real.) If you want to convert a passphrase to a key, use a suitable
// package like bcrypt or scrypt.
key, _ := hex.DecodeString("6368616e676520746869732070617373")
plaintext := []byte("exampleplaintext")
block, err := sm4.NewCipher(key)
if err != nil {
panic(err.Error())
}
// Never use more than 2^32 random nonces with a given key because of the risk of a repeat.
nonce := make([]byte, 12)
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
panic(err.Error())
}
sm4ccm, err := smcipher.NewCCM(block)
if err != nil {
panic(err.Error())
}
// You can encode the nonce and ciphertext with your own scheme
ciphertext := sm4ccm.Seal(nil, nonce, plaintext, nil)
fmt.Printf("%x %x\n", nonce, ciphertext)
}
func Example_decryptCCM() {
// Load your secret key from a safe place and reuse it across multiple
// Seal/Open calls. (Obviously don't use this example key for anything
// real.) If you want to convert a passphrase to a key, use a suitable
// package like bcrypt or scrypt.
key, _ := hex.DecodeString("6368616e676520746869732070617373")
// You can decode the nonce and ciphertext with your encoding scheme
ciphertext, _ := hex.DecodeString("aa5da19754e98c3a39787e8f0f8f73808b38ba31c9196772125e737f8d636483")
nonce, _ := hex.DecodeString("8f227cf05ad8b5c2902844e4")
block, err := sm4.NewCipher(key)
if err != nil {
panic(err.Error())
}
sm4ccm, err := smcipher.NewCCM(block)
if err != nil {
panic(err.Error())
}
plaintext, err := sm4ccm.Open(nil, nonce, ciphertext, nil)
if err != nil {
panic(err.Error())
}
fmt.Printf("%s\n", plaintext)
// Output: exampleplaintext
}
func Example_encryptCFB() {
// Load your secret key from a safe place and reuse it across multiple
// NewCipher calls. (Obviously don't use this example key for anything
// real.) If you want to convert a passphrase to a key, use a suitable
// package like bcrypt or scrypt.
key, _ := hex.DecodeString("6368616e676520746869732070617373")
plaintext := []byte("some plaintext")
block, err := sm4.NewCipher(key)
if err != nil {
panic(err)
}
// The IV needs to be unique, but not secure. Therefore it's common to
// include it at the beginning of the ciphertext.
ciphertext := make([]byte, sm4.BlockSize+len(plaintext))
iv := ciphertext[:sm4.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
stream := cipher.NewCFBEncrypter(block, iv)
stream.XORKeyStream(ciphertext[sm4.BlockSize:], plaintext)
// It's important to remember that ciphertexts must be authenticated
// (i.e. by using crypto/hmac) as well as being encrypted in order to
// be secure.
fmt.Printf("%x\n", ciphertext)
}
func Example_decryptCFB() {
// Load your secret key from a safe place and reuse it across multiple
// NewCipher calls. (Obviously don't use this example key for anything
// real.) If you want to convert a passphrase to a key, use a suitable
// package like bcrypt or scrypt.
key, _ := hex.DecodeString("6368616e676520746869732070617373")
ciphertext, _ := hex.DecodeString("37386876330ac7a6fa9d22d5b5dba22a779e3ed0e88307121a9808e65894")
block, err := sm4.NewCipher(key)
if err != nil {
panic(err)
}
// The IV needs to be unique, but not secure. Therefore it's common to
// include it at the beginning of the ciphertext.
if len(ciphertext) < sm4.BlockSize {
panic("ciphertext too short")
}
iv := ciphertext[:sm4.BlockSize]
ciphertext = ciphertext[sm4.BlockSize:]
stream := cipher.NewCFBDecrypter(block, iv)
// XORKeyStream can work in-place if the two arguments are the same.
stream.XORKeyStream(ciphertext, ciphertext)
fmt.Printf("%s", ciphertext)
// Output: some plaintext
}
func Example_modeCTR() {
// Load your secret key from a safe place and reuse it across multiple
// NewCipher calls. (Obviously don't use this example key for anything
// real.) If you want to convert a passphrase to a key, use a suitable
// package like bcrypt or scrypt.
key, _ := hex.DecodeString("6368616e676520746869732070617373")
plaintext := []byte("some plaintext")
block, err := sm4.NewCipher(key)
if err != nil {
panic(err)
}
// The IV needs to be unique, but not secure. Therefore it's common to
// include it at the beginning of the ciphertext.
ciphertext := make([]byte, sm4.BlockSize+len(plaintext))
iv := ciphertext[:sm4.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
stream := cipher.NewCTR(block, iv)
stream.XORKeyStream(ciphertext[sm4.BlockSize:], plaintext)
// It's important to remember that ciphertexts must be authenticated
// (i.e. by using crypto/hmac) as well as being encrypted in order to
// be secure.
// CTR mode is the same for both encryption and decryption, so we can
// also decrypt that ciphertext with NewCTR.
plaintext2 := make([]byte, len(plaintext))
stream = cipher.NewCTR(block, iv)
stream.XORKeyStream(plaintext2, ciphertext[sm4.BlockSize:])
fmt.Printf("%s\n", plaintext2)
// Output: some plaintext
}
func Example_modeOFB() {
// Load your secret key from a safe place and reuse it across multiple
// NewCipher calls. (Obviously don't use this example key for anything
// real.) If you want to convert a passphrase to a key, use a suitable
// package like bcrypt or scrypt.
key, _ := hex.DecodeString("6368616e676520746869732070617373")
plaintext := []byte("some plaintext")
block, err := sm4.NewCipher(key)
if err != nil {
panic(err)
}
// The IV needs to be unique, but not secure. Therefore it's common to
// include it at the beginning of the ciphertext.
ciphertext := make([]byte, sm4.BlockSize+len(plaintext))
iv := ciphertext[:sm4.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
stream := cipher.NewOFB(block, iv)
stream.XORKeyStream(ciphertext[sm4.BlockSize:], plaintext)
// It's important to remember that ciphertexts must be authenticated
// (i.e. by using crypto/hmac) as well as being encrypted in order to
// be secure.
// OFB mode is the same for both encryption and decryption, so we can
// also decrypt that ciphertext with NewOFB.
plaintext2 := make([]byte, len(plaintext))
stream = cipher.NewOFB(block, iv)
stream.XORKeyStream(plaintext2, ciphertext[sm4.BlockSize:])
fmt.Printf("%s\n", plaintext2)
// Output: some plaintext
}
func Example_streamReader() {
// Load your secret key from a safe place and reuse it across multiple
// NewCipher calls. (Obviously don't use this example key for anything
// real.) If you want to convert a passphrase to a key, use a suitable
// package like bcrypt or scrypt.
key, _ := hex.DecodeString("6368616e676520746869732070617373")
encrypted, _ := hex.DecodeString("38d03b4b50b6154e7437150b93fb0ef0")
bReader := bytes.NewReader(encrypted)
block, err := sm4.NewCipher(key)
if err != nil {
panic(err)
}
// If the key is unique for each ciphertext, then it's ok to use a zero
// IV.
var iv [sm4.BlockSize]byte
stream := cipher.NewOFB(block, iv[:])
reader := &cipher.StreamReader{S: stream, R: bReader}
// Copy the input to the output stream, decrypting as we go.
if _, err := io.Copy(os.Stdout, reader); err != nil {
panic(err)
}
// Note that this example is simplistic in that it omits any
// authentication of the encrypted data. If you were actually to use
// StreamReader in this manner, an attacker could flip arbitrary bits in
// the output.
// Output: some secret text
}
func Example_streamWriter() {
// Load your secret key from a safe place and reuse it across multiple
// NewCipher calls. (Obviously don't use this example key for anything
// real.) If you want to convert a passphrase to a key, use a suitable
// package like bcrypt or scrypt.
key, _ := hex.DecodeString("6368616e676520746869732070617373")
bReader := bytes.NewReader([]byte("some secret text"))
block, err := sm4.NewCipher(key)
if err != nil {
panic(err)
}
// If the key is unique for each ciphertext, then it's ok to use a zero
// IV.
var iv [sm4.BlockSize]byte
stream := cipher.NewOFB(block, iv[:])
var out bytes.Buffer
writer := &cipher.StreamWriter{S: stream, W: &out}
// Copy the input to the output buffer, encrypting as we go.
if _, err := io.Copy(writer, bReader); err != nil {
panic(err)
}
// Note that this example is simplistic in that it omits any
// authentication of the encrypted data. If you were actually to use
// StreamReader in this manner, an attacker could flip arbitrary bits in
// the decrypted result.
fmt.Printf("%x\n", out.Bytes())
// Output: 38d03b4b50b6154e7437150b93fb0ef0
}

View File

@ -11,6 +11,7 @@ import (
"github.com/emmansun/gmsm/kdf"
"github.com/emmansun/gmsm/sm3"
"github.com/emmansun/gmsm/sm9/bn256"
"golang.org/x/crypto/cryptobyte"
)
func bigFromHex(s string) *big.Int {
@ -149,6 +150,22 @@ func TestParseInvalidASN1(t *testing.T) {
}
}
func signMasterPrivateKeyFromHex(s string) (*SignMasterPrivateKey, error) {
kb, err := hex.DecodeString(s)
if err != nil {
return nil, err
}
var b cryptobyte.Builder
b.AddASN1BigInt(new(big.Int).SetBytes(kb))
kb, _ = b.Bytes()
testkey := new(SignMasterPrivateKey)
err = testkey.UnmarshalASN1(kb)
if err != nil {
return nil, err
}
return testkey, nil
}
// SM9 Appendix A
func TestSignSM9Sample(t *testing.T) {
expectedH := bigFromHex("823c4b21e4bd2dfe1ed92c606653e996668563152fc33f55d7bfbb9bd9705adb")
@ -166,13 +183,11 @@ func TestSignSM9Sample(t *testing.T) {
t.Fatal(err)
}
masterKey := new(SignMasterPrivateKey)
masterKey.D = bigFromHex("0130E78459D78545CB54C587E02CF480CE0B66340F319F348A1D5B1F2DC5F4")
p, err := new(bn256.G2).ScalarBaseMult(bn256.NormalizeScalar(masterKey.D.Bytes()))
masterKey, err := signMasterPrivateKeyFromHex("0130E78459D78545CB54C587E02CF480CE0B66340F319F348A1D5B1F2DC5F4")
if err != nil {
t.Fatal(err)
}
masterKey.MasterPublicKey = p
userKey, err := masterKey.GenerateUserKey(uid, hid)
if err != nil {
t.Fatal(err)
@ -211,13 +226,10 @@ func TestKeyExchangeSample(t *testing.T) {
expectedSignatureB := "3bb4bcee8139c960b4d6566db1e0d5f0b2767680e5e1bf934103e6c66e40ffee"
expectedSignatureA := "195d1b7256ba7e0e67c71202a25f8c94ff8241702c2f55d613ae1c6b98215172"
masterKey := new(EncryptMasterPrivateKey)
masterKey.D = bigFromHex("02E65B0762D042F51F0D23542B13ED8CFA2E9A0E7206361E013A283905E31F")
p, err := new(bn256.G1).ScalarBaseMult(bn256.NormalizeScalar(masterKey.D.Bytes()))
masterKey, err := encryptMasterPrivateKeyFromHex("02E65B0762D042F51F0D23542B13ED8CFA2E9A0E7206361E013A283905E31F")
if err != nil {
t.Fatal(err)
}
masterKey.MasterPublicKey = p
if hex.EncodeToString(masterKey.MasterPublicKey.Marshal()) != expectedPube {
t.Errorf("not expected master public key")
@ -481,6 +493,22 @@ func TestUnmarshalSM9KeyPackage(t *testing.T) {
}
}
func encryptMasterPrivateKeyFromHex(s string) (*EncryptMasterPrivateKey, error) {
kb, err := hex.DecodeString(s)
if err != nil {
return nil, err
}
var b cryptobyte.Builder
b.AddASN1BigInt(new(big.Int).SetBytes(kb))
kb, _ = b.Bytes()
testkey := new(EncryptMasterPrivateKey)
err = testkey.UnmarshalASN1(kb)
if err != nil {
return nil, err
}
return testkey, nil
}
// SM9 Appendix C
func TestWrapKeySM9Sample(t *testing.T) {
expectedMasterPublicKey := "787ed7b8a51f3ab84e0a66003f32da5c720b17eca7137d39abc66e3c80a892ff769de61791e5adc4b9ff85a31354900b202871279a8c49dc3f220f644c57a7b1"
@ -489,13 +517,10 @@ func TestWrapKeySM9Sample(t *testing.T) {
expectedCipher := "1edee2c3f465914491de44cefb2cb434ab02c308d9dc5e2067b4fed5aaac8a0f1c9b4c435eca35ab83bb734174c0f78fde81a53374aff3b3602bbc5e37be9a4c"
expectedKey := "4ff5cf86d2ad40c8f4bac98d76abdbde0c0e2f0a829d3f911ef5b2bce0695480"
masterKey := new(EncryptMasterPrivateKey)
masterKey.D = bigFromHex("01EDEE3778F441F8DEA3D9FA0ACC4E07EE36C93F9A08618AF4AD85CEDE1C22")
p, err := new(bn256.G1).ScalarBaseMult(bn256.NormalizeScalar(masterKey.D.Bytes()))
masterKey, err := encryptMasterPrivateKeyFromHex("01EDEE3778F441F8DEA3D9FA0ACC4E07EE36C93F9A08618AF4AD85CEDE1C22")
if err != nil {
t.Fatal(err)
}
masterKey.MasterPublicKey = p
if hex.EncodeToString(masterKey.MasterPublicKey.Marshal()) != expectedMasterPublicKey {
t.Errorf("not expected master public key")
}
@ -558,13 +583,10 @@ func TestEncryptSM9Sample(t *testing.T) {
expectedKey := "58373260f067ec48667c21c144f8bc33cd3049788651ffd5f738003e51df31174d0e4e402fd87f4581b612f74259db574f67ece6"
expectedCiphertext := "2445471164490618e1ee20528ff1d545b0f14c8bcaa44544f03dab5dac07d8ff42ffca97d57cddc05ea405f2e586feb3a6930715532b8000759f13059ed59ac0ba672387bcd6de5016a158a52bb2e7fc429197bcab70b25afee37a2b9db9f3671b5f5b0e951489682f3e64e1378cdd5da9513b1c"
masterKey := new(EncryptMasterPrivateKey)
masterKey.D = bigFromHex("01EDEE3778F441F8DEA3D9FA0ACC4E07EE36C93F9A08618AF4AD85CEDE1C22")
p, err := new(bn256.G1).ScalarBaseMult(bn256.NormalizeScalar(masterKey.D.Bytes()))
masterKey, err := encryptMasterPrivateKeyFromHex("01EDEE3778F441F8DEA3D9FA0ACC4E07EE36C93F9A08618AF4AD85CEDE1C22")
if err != nil {
t.Fatal(err)
}
masterKey.MasterPublicKey = p
if hex.EncodeToString(masterKey.MasterPublicKey.Marshal()) != expectedMasterPublicKey {
t.Errorf("not expected master public key")
}