Skip to content

Commit

Permalink
Support SM2 signature
Browse files Browse the repository at this point in the history
Support SM2withSM3 signature.
Fix cgo CFLAGS and LDFLAGS, should set CGO_CFLAGS and CGO_LDFLAGS when
build or test.
  • Loading branch information
dongbeiouba committed Jan 4, 2024
1 parent 82a881b commit 9451299
Show file tree
Hide file tree
Showing 23 changed files with 613 additions and 122 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,4 @@ jobs:
run: go build

- name: Test
run: LD_LIBRARY_PATH=/opt/tongsuo/lib go test ./...
run: LD_LIBRARY_PATH=/opt/tongsuo/lib CGO_CFLAGS="-Wall -I/opt/tongsuo/include -Wno-deprecated-declarations" CGO_LDFLAGS="-L/opt/tongsuo/lib" go test ./...
19 changes: 11 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

Tongsuo bindings for Go.

## Feature

- Symmetric algorithms: SM4
- Digital signature algorithms: SM2withSM3
- Hash algorithms: SM3, MD5, SHA1, SHA256
- Secure transport protocol: TLCP, TLSv1.0/1.1/1.2/1.3

## quick start

### Install Tongsuo
Expand All @@ -25,29 +32,25 @@ make install
On Linux:

```bash
LD_LIBRARY_PATH=/opt/tongsuo/lib go test ./...
LD_LIBRARY_PATH=/opt/tongsuo/lib CGO_CFLAGS="-I/opt/tongsuo/include -Wno-deprecated-declarations" CGO_LDFLAGS="-L/opt/tongsuo/lib" go test ./...
```

On MacOS:

```bash
DYLD_LIBRARY_PATH=/opt/tongsuo/lib go test ./...
DYLD_LIBRARY_PATH=/opt/tongsuo/lib CGO_CFLAGS="-I/opt/tongsuo/include -Wno-deprecated-declarations" CGO_LDFLAGS="-L/opt/tongsuo/lib" go test ./...
```

### Run example

On Linux:

```bash
cd examples/sm4
go build
LD_LIBRARY_PATH=/opt/tongsuo/lib ./sm4
LD_LIBRARY_PATH=/opt/tongsuo/lib CGO_CFLAGS="-I/opt/tongsuo/include -Wno-deprecated-declarations" CGO_LDFLAGS="-L/opt/tongsuo/lib" go run examples/sm4/sm4
```

On MacOS:

```bash
cd examples/sm4
go build
DYLD_LIBRARY_PATH=/opt/tongsuo/lib ./sm4
DYLD_LIBRARY_PATH=/opt/tongsuo/lib CGO_CFLAGS="-I/opt/tongsuo/include -Wno-deprecated-declarations" CGO_LDFLAGS="-L/opt/tongsuo/lib" go run examples/sm4/sm4.go
```
6 changes: 2 additions & 4 deletions build.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,8 @@

package tongsuogo

// #cgo linux CFLAGS: -I/opt/tongsuo/include -Wno-deprecated-declarations
// #cgo linux LDFLAGS: -L/opt/tongsuo/lib -lssl -lcrypto
// #cgo darwin CFLAGS: -I/opt/tongsuo/include -Wno-deprecated-declarations
// #cgo darwin LDFLAGS: -L/opt/tongsuo/lib -lssl -lcrypto
// #cgo linux LDFLAGS: -lssl -lcrypto
// #cgo darwin LDFLAGS: -lssl -lcrypto
// #cgo windows CFLAGS: -DWIN32_LEAN_AND_MEAN
// #cgo windows pkg-config: libssl libcrypto
import "C"
6 changes: 2 additions & 4 deletions build_static.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,8 @@

package tongsuogo

// #cgo linux CFLAGS: -I/opt/tongsuo/include -Wno-deprecated-declarations
// #cgo linux LDFLAGS: -extldflags -static -L/opt/tongsuo/lib -lssl -lcrypto
// #cgo darwin CFLAGS: -I/opt/tongsuo/include -Wno-deprecated-declarations
// #cgo darwin LDFLAGS: -extldflags -static -L/opt/tongsuo/lib -lssl -lcrypto
// #cgo linux LDFLAGS: -extldflags -static -lssl -lcrypto
// #cgo darwin LDFLAGS: -extldflags -static -lssl -lcrypto
// #cgo windows CFLAGS: -DWIN32_LEAN_AND_MEAN
// #cgo windows pkg-config: libssl libcrypto
import "C"
6 changes: 2 additions & 4 deletions crypto/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,8 @@

package crypto

// #cgo linux CFLAGS: -I/opt/tongsuo/include -Wno-deprecated-declarations
// #cgo linux LDFLAGS: -L/opt/tongsuo/lib -lcrypto
// #cgo darwin CFLAGS: -I/opt/tongsuo/include -Wno-deprecated-declarations
// #cgo darwin LDFLAGS: -L/opt/tongsuo/lib -lcrypto
// #cgo linux LDFLAGS: -lcrypto
// #cgo darwin LDFLAGS: -lcrypto
// #cgo windows CFLAGS: -DWIN32_LEAN_AND_MEAN
// #cgo windows pkg-config: libcrypto
import "C"
6 changes: 2 additions & 4 deletions crypto/build_static.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,8 @@

package crypto

// #cgo linux CFLAGS: -I/opt/tongsuo/include -Wno-deprecated-declarations
// #cgo linux LDFLAGS: -extldflags -static -L/opt/tongsuo/lib -lcrypto
// #cgo darwin CFLAGS: -I/opt/tongsuo/include -Wno-deprecated-declarations
// #cgo darwin LDFLAGS: -L/opt/tongsuo/lib -lcrypto
// #cgo linux LDFLAGS: -extldflags -static -lcrypto
// #cgo darwin LDFLAGS: -lcrypto
// #cgo windows CFLAGS: -DWIN32_LEAN_AND_MEAN
// #cgo windows pkg-config: libcrypto
import "C"
107 changes: 72 additions & 35 deletions crypto/key.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ var (
SHA1_Method Method = C.X_EVP_sha1()
SHA256_Method Method = C.X_EVP_sha256()
SHA512_Method Method = C.X_EVP_sha512()
SM3_Method Method = C.X_EVP_sm3()
)

// Constants for the various key types.
Expand All @@ -58,6 +59,7 @@ const (
KeyTypeX448 = NID_X448
KeyTypeED25519 = NID_ED25519
KeyTypeED448 = NID_ED448
KeyTypeSM2 = NID_sm2
)

type PublicKey interface {
Expand Down Expand Up @@ -124,7 +126,6 @@ func (key *pKey) SignPKCS1v15(method Method, data []byte) ([]byte, error) {

if key.KeyType() == KeyTypeED25519 {
// do ED specific one-shot sign

if method != nil || len(data) == 0 {
return nil, errors.New("signpkcs1v15: 0-length data or non-null digest")
}
Expand All @@ -146,21 +147,25 @@ func (key *pKey) SignPKCS1v15(method Method, data []byte) ([]byte, error) {

return sig[:sigblen], nil
} else {
if 1 != C.X_EVP_SignInit(ctx, method) {
if 1 != C.X_EVP_DigestSignInit(ctx, nil, method, nil, key.key) {
return nil, errors.New("signpkcs1v15: failed to init signature")
}

if len(data) > 0 {
if 1 != C.X_EVP_SignUpdate(
ctx, unsafe.Pointer(&data[0]), C.uint(len(data))) {
if 1 != C.X_EVP_DigestSignUpdate(
ctx, unsafe.Pointer(&data[0]), C.size_t(len(data))) {
return nil, errors.New("signpkcs1v15: failed to update signature")
}
}
sig := make([]byte, C.X_EVP_PKEY_size(key.key))
var sigblen C.uint
if 1 != C.X_EVP_SignFinal(ctx,
((*C.uchar)(unsafe.Pointer(&sig[0]))), &sigblen, key.key) {

var sigblen C.size_t = C.size_t(C.X_EVP_PKEY_size(key.key))
sig := make([]byte, sigblen)

if 1 != C.X_EVP_DigestSignFinal(ctx,
((*C.uchar)(unsafe.Pointer(&sig[0]))), &sigblen) {
return nil, errors.New("signpkcs1v15: failed to finalize signature")
}

return sig[:sigblen], nil
}
}
Expand Down Expand Up @@ -191,19 +196,22 @@ func (key *pKey) VerifyPKCS1v15(method Method, data, sig []byte) error {
return nil

} else {
if 1 != C.X_EVP_VerifyInit(ctx, method) {
if 1 != C.X_EVP_DigestVerifyInit(ctx, nil, method, nil, key.key) {
return errors.New("verifypkcs1v15: failed to init verify")
}

if len(data) > 0 {
if 1 != C.X_EVP_VerifyUpdate(
ctx, unsafe.Pointer(&data[0]), C.uint(len(data))) {
if 1 != C.X_EVP_DigestVerifyUpdate(
ctx, unsafe.Pointer(&data[0]), C.size_t(len(data))) {
return errors.New("verifypkcs1v15: failed to update verify")
}
}
if 1 != C.X_EVP_VerifyFinal(ctx,
((*C.uchar)(unsafe.Pointer(&sig[0]))), C.uint(len(sig)), key.key) {

if 1 != C.X_EVP_DigestVerifyFinal(ctx,
((*C.uchar)(unsafe.Pointer(&sig[0]))), C.size_t(len(sig))) {
return errors.New("verifypkcs1v15: failed to finalize verify")
}

return nil
}
}
Expand Down Expand Up @@ -293,6 +301,13 @@ func LoadPrivateKeyFromPEM(pem_block []byte) (PrivateKey, error) {
runtime.SetFinalizer(p, func(p *pKey) {
C.X_EVP_PKEY_free(p.key)
})

if C.X_EVP_PKEY_is_sm2(p.key) == 1 {
if C.EVP_PKEY_set_alias_type(p.key, C.EVP_PKEY_SM2) != 1 {

Check failure on line 306 in crypto/key.go

View workflow job for this annotation

GitHub Actions / build

could not determine kind of name for C.EVP_PKEY_set_alias_type

Check failure on line 306 in crypto/key.go

View workflow job for this annotation

GitHub Actions / build

could not determine kind of name for C.EVP_PKEY_set_alias_type
return nil, errors.New("failed set alias type")
}
}

return p, nil
}

Expand Down Expand Up @@ -438,6 +453,8 @@ const (
Secp384r1 EllipticCurve = C.NID_secp384r1
// P-521: NIST/SECG curve over a 521 bit prime field
Secp521r1 EllipticCurve = C.NID_secp521r1
// SM2: GB/T 32918-2017
Sm2Curve EllipticCurve = C.NID_sm2
)

// GenerateECKey generates a new elliptic curve private key on the speicified
Expand All @@ -451,43 +468,63 @@ func GenerateECKey(curve EllipticCurve) (PrivateKey, error) {
}
defer C.EVP_PKEY_CTX_free(paramCtx)

// Intialize the parameter generation
if int(C.EVP_PKEY_paramgen_init(paramCtx)) != 1 {
return nil, errors.New("failed initializing EC parameter generation context")
if curve == Sm2Curve {
if C.EVP_PKEY_keygen_init(paramCtx) != 1 {
return nil, errors.New("failed initializing EC key generation context")
}
} else {
// Intialize the parameter generation
if int(C.EVP_PKEY_paramgen_init(paramCtx)) != 1 {
return nil, errors.New("failed initializing EC parameter generation context")
}
}

// Set curve in EC parameter generation context
if int(C.X_EVP_PKEY_CTX_set_ec_paramgen_curve_nid(paramCtx, C.int(curve))) != 1 {
return nil, errors.New("failed setting curve in EC parameter generation context")
}

// Create parameter object
var params *C.EVP_PKEY
if int(C.EVP_PKEY_paramgen(paramCtx, &params)) != 1 {
return nil, errors.New("failed creating EC key generation parameters")
}
defer C.EVP_PKEY_free(params)
var privKey *C.EVP_PKEY

// Create context for the key generation
keyCtx := C.EVP_PKEY_CTX_new(params, nil)
if keyCtx == nil {
return nil, errors.New("failed creating EC key generation context")
}
defer C.EVP_PKEY_CTX_free(keyCtx)
if curve == Sm2Curve {
if int(C.EVP_PKEY_keygen(paramCtx, &privKey)) != 1 {
return nil, errors.New("failed generating EC private key")
}
} else {
// Create parameter object
var params *C.EVP_PKEY
if int(C.EVP_PKEY_paramgen(paramCtx, &params)) != 1 {
return nil, errors.New("failed creating EC key generation parameters")
}
defer C.EVP_PKEY_free(params)

// Generate the key
var privKey *C.EVP_PKEY
if int(C.EVP_PKEY_keygen_init(keyCtx)) != 1 {
return nil, errors.New("failed initializing EC key generation context")
}
if int(C.EVP_PKEY_keygen(keyCtx, &privKey)) != 1 {
return nil, errors.New("failed generating EC private key")
// Create context for the key generation
keyCtx := C.EVP_PKEY_CTX_new(params, nil)
if keyCtx == nil {
return nil, errors.New("failed creating EC key generation context")
}
defer C.EVP_PKEY_CTX_free(keyCtx)

if int(C.EVP_PKEY_keygen_init(keyCtx)) != 1 {
return nil, errors.New("failed initializing EC key generation context")
}

if int(C.EVP_PKEY_keygen(keyCtx, &privKey)) != 1 {
return nil, errors.New("failed generating EC private key")
}
}

p := &pKey{key: privKey}
runtime.SetFinalizer(p, func(p *pKey) {
C.X_EVP_PKEY_free(p.key)
})

if curve == Sm2Curve {
if C.EVP_PKEY_set_alias_type(p.key, C.EVP_PKEY_SM2) != 1 {
return nil, errors.New("failed set alias type")
}
}

return p, nil
}

Expand Down
Loading

0 comments on commit 9451299

Please sign in to comment.