diff --git a/pkcs8/example_test.go b/pkcs8/example_test.go index 479cc71..2d947a1 100644 --- a/pkcs8/example_test.go +++ b/pkcs8/example_test.go @@ -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 +} diff --git a/sm3/example_test.go b/sm3/example_test.go new file mode 100644 index 0000000..1bd49f9 --- /dev/null +++ b/sm3/example_test.go @@ -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)) +} diff --git a/sm4/example_test.go b/sm4/example_test.go index 36505b7..d3e29a2 100644 --- a/sm4/example_test.go +++ b/sm4/example_test.go @@ -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 +} diff --git a/sm9/sm9_test.go b/sm9/sm9_test.go index 6d283e0..9dad51a 100644 --- a/sm9/sm9_test.go +++ b/sm9/sm9_test.go @@ -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") }