├── sm3 ├── ifile ├── sm3_test.go └── sm3.go ├── gmtls ├── websvr │ ├── img │ │ └── autoswitchlogic.png │ ├── certs │ │ ├── SM2_CA_KEY.pem │ │ ├── sm2_auth_key.pem │ │ ├── sm2_enc_key.pem │ │ ├── sm2_sign_key.pem │ │ ├── SM2_CA.cer │ │ ├── sm2_enc_cert.cer │ │ ├── sm2_auth_cert.cer │ │ ├── sm2_sign_cert.cer │ │ ├── rsa_auth_cert.cer │ │ ├── RSA_CA.cer │ │ ├── rsa_sign.cer │ │ ├── rsa_auth_key.pem │ │ ├── rsa_sign_key.pem │ │ └── RSA_CA_KEY.pem │ ├── websvr_test.go │ ├── websvr.go │ └── README.md ├── gmcredentials │ ├── testdata │ │ ├── sign.key │ │ ├── user.key │ │ ├── encrypt.key │ │ ├── ca.cert │ │ ├── user.cert │ │ ├── encrypt.cert │ │ └── sign.cert │ ├── echo │ │ ├── echo.proto │ │ └── echo.pb.go │ ├── credentials_util_go18.go │ ├── credentials_test.go │ └── credentials.go ├── auto_switch_config.go ├── simple_round_trip.go ├── http_client.go ├── gm_handshake_messages.go ├── alert.go ├── auth.go ├── ticket.go └── http_client_test.go ├── go.mod ├── .gitignore ├── pkcs12 ├── errors.go ├── mac.go ├── bmp-string.go ├── pkcs12_test.go ├── safebags.go ├── crypto.go ├── pbkdf.go ├── rc2.go └── pkcs8.go ├── .travis.yml ├── azure-pipelines.yml ├── sm4 ├── padding │ ├── bloc_cryptor_test.go │ ├── bloc_cryptor.go │ ├── pkcs7_padding_io_test.go │ ├── README.md │ └── pkcs7_padding_io.go ├── sm4_gcm_test.go ├── utils.go ├── sm4_test.go └── sm4_gcm.go ├── sm2 ├── utils.go └── sm2_test.go ├── README.md ├── CHANGELOG.md ├── API使用说明.md ├── x509 ├── pkcs1.go ├── pkcs7_test.go ├── cert_pool.go ├── ber.go └── utils.go └── go.sum /sm3/ifile: -------------------------------------------------------------------------------- 1 | test -------------------------------------------------------------------------------- /gmtls/websvr/img/autoswitchlogic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tjfoc/gmsm/HEAD/gmtls/websvr/img/autoswitchlogic.png -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/tjfoc/gmsm 2 | 3 | go 1.14 4 | 5 | require ( 6 | github.com/golang/protobuf v1.4.2 7 | golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee 8 | golang.org/x/net v0.0.0-20201010224723-4f7140c49acb 9 | google.golang.org/grpc v1.31.0 10 | ) 11 | -------------------------------------------------------------------------------- /gmtls/gmcredentials/testdata/sign.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIGHAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQgxG5EaEBHaq1vHL2D 3 | DOEQ9dCa3nqSXxBs4ZHIVH7sOaahRANCAASqGDkM9U2uwvaRceBzqFmtQTLmhQaW 4 | sGtA6QBD4jlZ0Vog13HVHEhTXbnaJYsfVjoxIK0ZGdKIgzK7gSUbVeLp 5 | -----END PRIVATE KEY----- 6 | -------------------------------------------------------------------------------- /gmtls/gmcredentials/testdata/user.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIGHAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQg9wokbsEkt3Y7V1/x 3 | acjfxL4xyBjtFyJU4EEi2GF/OIChRANCAATonWvfNyA4L44dhOmXXNuATGnlwwFb 4 | txoNVms+FiIw7yP5NEkHmbhMAjiANvrx3W3BhTtXmdYWclMKzr6xwd54 5 | -----END PRIVATE KEY----- 6 | -------------------------------------------------------------------------------- /gmtls/gmcredentials/testdata/encrypt.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIGHAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQg44YAGQHnMf28yNaI 3 | 4yuSoA4VQYfaz8RF47VFeSnbbgGhRANCAAT/RTpRPyZ2AqaNl3EO+YzgGf51lriY 4 | qhwp7OfDD+SF5jUquSaoC2L51zbH9FtCRkGMJW0+kBerZ17d86h7cxlM 5 | -----END PRIVATE KEY----- 6 | -------------------------------------------------------------------------------- /gmtls/gmcredentials/echo/echo.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package echo; 4 | 5 | service Echo{ 6 | rpc Echo(EchoRequest) returns (EchoResponse){} 7 | } 8 | 9 | message EchoRequest{ 10 | string req = 1; 11 | } 12 | 13 | message EchoResponse{ 14 | string result = 1; 15 | } 16 | -------------------------------------------------------------------------------- /gmtls/websvr/certs/SM2_CA_KEY.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQg8/o/oC+JT0Nv2T0K 3 | AdZ8OiH9YGVIGsnx0xfDK+lXzpagCgYIKoEcz1UBgi2hRANCAAS6OFCNygoH2f4O 4 | nPbV570rydtVcTvAUYOo/Mk9dcKsvEwDu+WZ2Lw8Ef4PCcqgm6B6+qo86x4AKXjm 5 | pTzXvXf9 6 | -----END PRIVATE KEY----- 7 | -------------------------------------------------------------------------------- /gmtls/websvr/certs/sm2_auth_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgqSvMdgsT9VlcC7fF 3 | uewfAWp4eNoLT3zhTZisHsZ2WS+gCgYIKoEcz1UBgi2hRANCAAQVZNo44m183rOc 4 | 7tZ4qHL0tnYSL1RXnzdXCiUfH36Kku1yJ9DKKm6f5BtOPUzWx3YEy0UrrzXucie1 5 | PdwKFtWm 6 | -----END PRIVATE KEY----- 7 | -------------------------------------------------------------------------------- /gmtls/websvr/certs/sm2_enc_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgb8tUl8wJ17FqiOSp 3 | pHwKa1pOgxQhAP0VoPe/EU0cGAqgCgYIKoEcz1UBgi2hRANCAARipb11eBDLluL8 4 | OMWZOfdyOXKsvWMu40pEW2nFdUPxWpRw+akHNz8Aat6Mbr5k9fUiG3gbC/SYG44t 5 | d40YCWFb 6 | -----END PRIVATE KEY----- 7 | -------------------------------------------------------------------------------- /gmtls/websvr/certs/sm2_sign_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQguBgnxgDxfYC9AM3v 3 | C2oQ7W54T7XLS3Dfoiv/8bQQXZ2gCgYIKoEcz1UBgi2hRANCAAQGNFBLmSXwgypy 4 | AFln6qlgaV+a6H1RaTBrpF12ciuY+bna9ewBXbAdM2wYPBxq8ifZfl/TngvX8TAq 5 | rNwx8prv 6 | -----END PRIVATE KEY----- 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | #Ignore thumbnails created by Windows 3 | Thumbs.db 4 | #Ignore files built by Visual Studio 5 | *.obj 6 | *.exe 7 | *.pdb 8 | *.user 9 | *.aps 10 | *.pch 11 | *.vspscc 12 | *_i.c 13 | *_p.c 14 | *.ncb 15 | *.suo 16 | *.tlb 17 | *.tlh 18 | *.bak 19 | *.cache 20 | *.ilk 21 | *.log 22 | [Bb]in 23 | [Dd]ebug*/ 24 | *.lib 25 | *.sbr 26 | obj/ 27 | [Rr]elease*/ 28 | _ReSharper*/ 29 | [Tt]est[Rr]esult* 30 | .vs/ 31 | #Nuget packages folder 32 | packages/ 33 | *.pem 34 | .idea -------------------------------------------------------------------------------- /gmtls/websvr/certs/SM2_CA.cer: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIB3jCCAYOgAwIBAgIIAs4Fs2xzPucwCgYIKoEcz1UBg3UwQjELMAkGA1UEBhMC 3 | Q04xDzANBgNVBAgMBua1meaxnzEPMA0GA1UEBwwG5p2t5beeMREwDwYDVQQKDAjm 4 | tYvor5VDQTAeFw0yMTA1MzAwNjU1MDJaFw0zMTA1MzAwNjU1MDJaMEIxCzAJBgNV 5 | BAYTAkNOMQ8wDQYDVQQIDAbmtZnmsZ8xDzANBgNVBAcMBuadreW3njERMA8GA1UE 6 | CgwI5rWL6K+VQ0EwWTATBgcqhkjOPQIBBggqgRzPVQGCLQNCAAS6OFCNygoH2f4O 7 | nPbV570rydtVcTvAUYOo/Mk9dcKsvEwDu+WZ2Lw8Ef4PCcqgm6B6+qo86x4AKXjm 8 | pTzXvXf9o2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV 9 | HQ4EFgQUkdPXpvl7d/x5XcvSMqy7QASw+P8wHwYDVR0jBBgwFoAUkdPXpvl7d/x5 10 | XcvSMqy7QASw+P8wCgYIKoEcz1UBg3UDSQAwRgIhAO5iMN3sedKg0z6yk4SVnkNm 11 | 0c8FGV/Ttoa9N+hUlC2RAiEA2TdKM4glaYOdXIDoFTbmIeFZp/2Hxk3JWYpef8m+ 12 | AP0= 13 | -----END CERTIFICATE----- 14 | -------------------------------------------------------------------------------- /gmtls/websvr/certs/sm2_enc_cert.cer: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIB4zCCAYqgAwIBAgIIAs4Fs4MsOxcwCgYIKoEcz1UBg3UwQjELMAkGA1UEBhMC 3 | Q04xDzANBgNVBAgMBua1meaxnzEPMA0GA1UEBwwG5p2t5beeMREwDwYDVQQKDAjm 4 | tYvor5VDQTAeFw0yMTA1MzAxMDM2MjRaFw0zMTA1MzAwNjU1MDJaMFoxCzAJBgNV 5 | BAYTAkNOMQ8wDQYDVQQIDAbmtZnmsZ8xDzANBgNVBAcMBuadreW3njEVMBMGA1UE 6 | CgwM5rWL6K+V5YWs5Y+4MRIwEAYDVQQDEwlsb2NhbGhvc3QwWTATBgcqhkjOPQIB 7 | BggqgRzPVQGCLQNCAARipb11eBDLluL8OMWZOfdyOXKsvWMu40pEW2nFdUPxWpRw 8 | +akHNz8Aat6Mbr5k9fUiG3gbC/SYG44td40YCWFbo1IwUDAOBgNVHQ8BAf8EBAMC 9 | BDAwHQYDVR0OBBYEFGzJ+VHUzO6lbLYBkkmlYXvJawiLMB8GA1UdIwQYMBaAFJHT 10 | 16b5e3f8eV3L0jKsu0AEsPj/MAoGCCqBHM9VAYN1A0cAMEQCIA1D0uErueuHk9pa 11 | Q/QYFKr5fDqM3NmSkw8C2AdUB3fQAiAuInwpog9I1wpBAojaGuNlpUroCUnMf1TO 12 | yYtCmmMgTw== 13 | -----END CERTIFICATE----- 14 | -------------------------------------------------------------------------------- /gmtls/websvr/certs/sm2_auth_cert.cer: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIB7zCCAZSgAwIBAgIIAs4GXZKiyLcwCgYIKoEcz1UBg3UwQjELMAkGA1UEBhMC 3 | Q04xDzANBgNVBAgMBua1meaxnzEPMA0GA1UEBwwG5p2t5beeMREwDwYDVQQKDAjm 4 | tYvor5VDQTAeFw0yMTA2MDMxNDQwMTFaFw0zMTA1MzAwNjU1MDJaMEUxCzAJBgNV 5 | BAYTAkNOMQ8wDQYDVQQIDAbmtZnmsZ8xDzANBgNVBAcMBuadreW3njEUMBIGA1UE 6 | AxMLY2xpZW50IGF1dGgwWTATBgcqhkjOPQIBBggqgRzPVQGCLQNCAAQVZNo44m18 7 | 3rOc7tZ4qHL0tnYSL1RXnzdXCiUfH36Kku1yJ9DKKm6f5BtOPUzWx3YEy0UrrzXu 8 | cie1PdwKFtWmo3EwbzAOBgNVHQ8BAf8EBAMCBsAwHQYDVR0lBBYwFAYIKwYBBQUH 9 | AwEGCCsGAQUFBwMCMB0GA1UdDgQWBBQhXmk/MqqLj+FwJxB/1ETt8OPxJTAfBgNV 10 | HSMEGDAWgBSR09em+Xt3/Hldy9IyrLtABLD4/zAKBggqgRzPVQGDdQNJADBGAiEA 11 | xSFUrnvdHCbljJK8ng5o2ONOtOQdDdWsKSNqKszsULQCIQCNdt/DOCL5NAuro3vy 12 | ND0QommjjXvYTX1ku2k903oLog== 13 | -----END CERTIFICATE----- 14 | -------------------------------------------------------------------------------- /gmtls/gmcredentials/testdata/ca.cert: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIB9DCCAZqgAwIBAgIJAMQooIBlaTnvMAoGCCqBHM9VAYN1ME0xCzAJBgNVBAYT 3 | AkNOMRIwEAYDVQQIDAlTaGFuZyBIYWkxFDASBgNVBAoMC2V4YW1wbGUuY29tMRQw 4 | EgYDVQQDDAtleGFtcGxlLmNvbTAeFw0yMDEwMjYxNDI3MjlaFw0zMDEwMjQxNDI3 5 | MjlaME0xCzAJBgNVBAYTAkNOMRIwEAYDVQQIDAlTaGFuZyBIYWkxFDASBgNVBAoM 6 | C2V4YW1wbGUuY29tMRQwEgYDVQQDDAtleGFtcGxlLmNvbTBZMBMGByqGSM49AgEG 7 | CCqBHM9VAYItA0IABLELsuZvJIROBlgOYcokYjrtZeMRJCmXwX+ihD6vl/pOsqnj 8 | PmCOPi4CX8qfeXC9q1Q4eJMaKQ8iZEJBIUrd/FmjYzBhMB0GA1UdDgQWBBR471SI 9 | sesZy/B92W6NbWerioEcrTAfBgNVHSMEGDAWgBR471SIsesZy/B92W6NbWerioEc 10 | rTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAKBggqgRzPVQGDdQNI 11 | ADBFAiBG/puLQVoWKUwzdWln0wYuM8ELjZD+A5ivY5hMte3p7wIhAMfZwX2aqMGJ 12 | JFp6NJClZNEwQ/WJTJmb0ony73Q4f7tS 13 | -----END CERTIFICATE----- 14 | -------------------------------------------------------------------------------- /gmtls/websvr/certs/sm2_sign_cert.cer: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICAzCCAamgAwIBAgIIAs4Fs4MsM4cwCgYIKoEcz1UBg3UwQjELMAkGA1UEBhMC 3 | Q04xDzANBgNVBAgMBua1meaxnzEPMA0GA1UEBwwG5p2t5beeMREwDwYDVQQKDAjm 4 | tYvor5VDQTAeFw0yMTA1MzAxMDM2MjRaFw0zMTA1MzAwNjU1MDJaMFoxCzAJBgNV 5 | BAYTAkNOMQ8wDQYDVQQIDAbmtZnmsZ8xDzANBgNVBAcMBuadreW3njEVMBMGA1UE 6 | CgwM5rWL6K+V5YWs5Y+4MRIwEAYDVQQDEwlsb2NhbGhvc3QwWTATBgcqhkjOPQIB 7 | BggqgRzPVQGCLQNCAAQGNFBLmSXwgypyAFln6qlgaV+a6H1RaTBrpF12ciuY+bna 8 | 9ewBXbAdM2wYPBxq8ifZfl/TngvX8TAqrNwx8prvo3EwbzAOBgNVHQ8BAf8EBAMC 9 | BsAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMB0GA1UdDgQWBBSaOetP 10 | WqlSUA8kI4USxm7Q8AuFRTAfBgNVHSMEGDAWgBSR09em+Xt3/Hldy9IyrLtABLD4 11 | /zAKBggqgRzPVQGDdQNIADBFAiAWE82lXaNtLlNOLAluzlJUpUnodpDQ121tgX5f 12 | ZnKVwQIhAKpId+6AumorqW0QQcgaPrwP3OyJed1XPLxvOYkMmSdT 13 | -----END CERTIFICATE----- 14 | -------------------------------------------------------------------------------- /pkcs12/errors.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package pkcs12 6 | 7 | import "errors" 8 | 9 | var ( 10 | // ErrDecryption represents a failure to decrypt the input. 11 | ErrDecryption = errors.New("go-pkcs12: decryption error, incorrect padding") 12 | 13 | // ErrIncorrectPassword is returned when an incorrect password is detected. 14 | // Usually, P12/PFX data is signed to be able to verify the password. 15 | ErrIncorrectPassword = errors.New("go-pkcs12: decryption password incorrect") 16 | ) 17 | 18 | // NotImplementedError indicates that the input is not currently supported. 19 | type NotImplementedError string 20 | 21 | func (e NotImplementedError) Error() string { 22 | return "go-pkcs12: " + string(e) 23 | } 24 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | dist: bionic 3 | language: go 4 | os: 5 | - linux 6 | - osx 7 | osx_image: xcode11 8 | go: 9 | - 1.14.x 10 | - 1.15.x 11 | before_install: 12 | - export GO111MODULE=on 13 | install: 14 | - go get -u golang.org/x/lint/golint 15 | - export golint=$(go list -f {{.Target}} golang.org/x/lint/golint) 16 | - export GODEBUG=x509ignoreCN=0 17 | - go mod vendor 18 | - go build -v ./sm2 19 | - go build -v ./sm3 20 | - go build -v ./sm4 21 | - go build -v ./x509 22 | - go build -v ./pkcs12 23 | - go build -v ./gmtls/gmcredentials 24 | - go build -v ./gmtls/gmcredentials/echo 25 | - go build -v ./gmtls/websvr 26 | script: 27 | - go vet ./sm2 28 | - go vet ./sm3 29 | - go vet ./sm4 30 | - go vet ./x509 31 | - go vet ./pkcs12 32 | - go vet ./gmtls/gmcredentials 33 | - go vet ./gmtls/websvr 34 | - golint . 35 | - go test -v ./... 36 | -------------------------------------------------------------------------------- /gmtls/gmcredentials/testdata/user.cert: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICVDCCAfugAwIBAgICEAAwCgYIKoEcz1UBg3UwTTELMAkGA1UEBhMCQ04xEjAQ 3 | BgNVBAgMCVNoYW5nIEhhaTEUMBIGA1UECgwLZXhhbXBsZS5jb20xFDASBgNVBAMM 4 | C2V4YW1wbGUuY29tMB4XDTIwMTAyNjE0MjcyOVoXDTIxMTAyNjE0MjcyOVowUjEL 5 | MAkGA1UEBhMCQ04xEjAQBgNVBAgMCVNoYW5nIEhhaTEUMBIGA1UECgwLZXhhbXBs 6 | ZS5jb20xGTAXBgNVBAMMEHRlc3QuZXhhbXBsZS5jb20wWTATBgcqhkjOPQIBBggq 7 | gRzPVQGCLQNCAATonWvfNyA4L44dhOmXXNuATGnlwwFbtxoNVms+FiIw7yP5NEkH 8 | mbhMAjiANvrx3W3BhTtXmdYWclMKzr6xwd54o4HFMIHCMAkGA1UdEwQCMAAwEQYJ 9 | YIZIAYb4QgEBBAQDAgWgMDMGCWCGSAGG+EIBDQQmFiRPcGVuU1NMIEdlbmVyYXRl 10 | ZCBDbGllbnQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFPi+UWQ/MQI3R9BR7qAKVMcu 11 | /W+hMB8GA1UdIwQYMBaAFHjvVIix6xnL8H3Zbo1tZ6uKgRytMA4GA1UdDwEB/wQE 12 | AwIF4DAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQwCgYIKoEcz1UBg3UD 13 | RwAwRAIgegBDw4lqQIIcfe20R8j+B7i9BtQx9vSDjL47nNRAbmoCIFipPgm0FyHK 14 | Xh2FFAQA4TfDK+geQYdUTDtR6AnCDZST 15 | -----END CERTIFICATE----- 16 | -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | pool: 2 | vmImage: 'ubuntu-18.04' 3 | 4 | strategy: 5 | matrix: 6 | LTS: 7 | goVersion: '1.15' 8 | latest: 9 | goVersion: '1.14' 10 | 11 | steps: 12 | - task: GoTool@0 13 | inputs: 14 | version: $(goVersion) 15 | - script: export GODEBUG=x509ignoreCN=0 16 | - script: go build -v ./sm2 17 | - script: go build -v ./sm3 18 | - script: go build -v ./sm4 19 | - script: go build -v ./x509 20 | - script: go build -v ./pkcs12 21 | - script: go build -v ./gmtls/gmcredentials 22 | - script: go build -v ./gmtls/gmcredentials/echo 23 | - script: go build -v ./gmtls/websvr 24 | - script: go mod vendor 25 | - script: go vet ./sm2 26 | - script: go vet ./sm3 27 | - script: go vet ./sm4 28 | - script: go vet ./x509 29 | - script: go vet ./pkcs12 30 | - script: go vet ./gmtls/gmcredentials 31 | - script: go vet ./gmtls/websvr 32 | - script: go test -v ./... 33 | displayName: go test recursive 34 | 35 | -------------------------------------------------------------------------------- /gmtls/auto_switch_config.go: -------------------------------------------------------------------------------- 1 | package gmtls 2 | 3 | // NewBasicAutoSwitchConfig 返回一个实现了GMSSL/TLS自动切换的配置 4 | // 5 | // sm2SigCert: SM2 签名密钥对、证书 6 | // sm2EncCert: SM2 加密密钥对、证书 7 | // stdCert: RSA/ECC 标准的密钥对、证书 8 | // 9 | // return: 最基础的Config对象 10 | func NewBasicAutoSwitchConfig(sm2SigCert, sm2EncCert, stdCert *Certificate) (*Config, error) { 11 | fncGetSignCertKeypair := func(info *ClientHelloInfo) (*Certificate, error) { 12 | gmFlag := false 13 | // 检查支持协议中是否包含GMSSL 14 | for _, v := range info.SupportedVersions { 15 | if v == VersionGMSSL { 16 | gmFlag = true 17 | break 18 | } 19 | } 20 | 21 | if gmFlag { 22 | return sm2SigCert, nil 23 | } else { 24 | return stdCert, nil 25 | } 26 | } 27 | 28 | fncGetEncCertKeypair := func(info *ClientHelloInfo) (*Certificate, error) { 29 | return sm2EncCert, nil 30 | } 31 | support := NewGMSupport() 32 | support.EnableMixMode() 33 | return &Config{ 34 | GMSupport: support, 35 | GetCertificate: fncGetSignCertKeypair, 36 | GetKECertificate: fncGetEncCertKeypair, 37 | }, nil 38 | } 39 | -------------------------------------------------------------------------------- /gmtls/gmcredentials/testdata/encrypt.cert: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICqzCCAlGgAwIBAgICEAAwCgYIKoEcz1UBg3UwTTELMAkGA1UEBhMCQ04xEjAQ 3 | BgNVBAgMCVNoYW5nIEhhaTEUMBIGA1UECgwLZXhhbXBsZS5jb20xFDASBgNVBAMM 4 | C2V4YW1wbGUuY29tMB4XDTIwMTAyNjE0MjcyOVoXDTIxMTAyNjE0MjcyOVowUjEL 5 | MAkGA1UEBhMCQ04xEjAQBgNVBAgMCVNoYW5nIEhhaTEUMBIGA1UECgwLZXhhbXBs 6 | ZS5jb20xGTAXBgNVBAMMEHRlc3QuZXhhbXBsZS5jb20wWTATBgcqhkjOPQIBBggq 7 | gRzPVQGCLQNCAAT/RTpRPyZ2AqaNl3EO+YzgGf51lriYqhwp7OfDD+SF5jUquSao 8 | C2L51zbH9FtCRkGMJW0+kBerZ17d86h7cxlMo4IBGjCCARYwCQYDVR0TBAIwADAR 9 | BglghkgBhvhCAQEEBAMCBkAwMwYJYIZIAYb4QgENBCYWJE9wZW5TU0wgR2VuZXJh 10 | dGVkIFNlcnZlciBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUCVs5pTt4j4EAvDwwqoEE 11 | mU4GjhMwfQYDVR0jBHYwdIAUeO9UiLHrGcvwfdlujW1nq4qBHK2hUaRPME0xCzAJ 12 | BgNVBAYTAkNOMRIwEAYDVQQIDAlTaGFuZyBIYWkxFDASBgNVBAoMC2V4YW1wbGUu 13 | Y29tMRQwEgYDVQQDDAtleGFtcGxlLmNvbYIJAMQooIBlaTnvMA4GA1UdDwEB/wQE 14 | AwIFIDATBgNVHSUEDDAKBggrBgEFBQcDATAKBggqgRzPVQGDdQNIADBFAiA+3xzT 15 | MFqyKrdPcBVxOPHc/db5uAEIvRZUDYmjxWnbkAIhALOGXm49WI2X4PpOYPhQGiwp 16 | LKG+pd6+7i925lHNY5A9 17 | -----END CERTIFICATE----- 18 | -------------------------------------------------------------------------------- /gmtls/gmcredentials/testdata/sign.cert: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICqjCCAlGgAwIBAgICEAAwCgYIKoEcz1UBg3UwTTELMAkGA1UEBhMCQ04xEjAQ 3 | BgNVBAgMCVNoYW5nIEhhaTEUMBIGA1UECgwLZXhhbXBsZS5jb20xFDASBgNVBAMM 4 | C2V4YW1wbGUuY29tMB4XDTIwMTAyNjE0MjcyOVoXDTIxMTAyNjE0MjcyOVowUjEL 5 | MAkGA1UEBhMCQ04xEjAQBgNVBAgMCVNoYW5nIEhhaTEUMBIGA1UECgwLZXhhbXBs 6 | ZS5jb20xGTAXBgNVBAMMEHRlc3QuZXhhbXBsZS5jb20wWTATBgcqhkjOPQIBBggq 7 | gRzPVQGCLQNCAASqGDkM9U2uwvaRceBzqFmtQTLmhQaWsGtA6QBD4jlZ0Vog13HV 8 | HEhTXbnaJYsfVjoxIK0ZGdKIgzK7gSUbVeLpo4IBGjCCARYwCQYDVR0TBAIwADAR 9 | BglghkgBhvhCAQEEBAMCBkAwMwYJYIZIAYb4QgENBCYWJE9wZW5TU0wgR2VuZXJh 10 | dGVkIFNlcnZlciBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUWewLKGmXW5FINNqKnq8b 11 | svOsjpYwfQYDVR0jBHYwdIAUeO9UiLHrGcvwfdlujW1nq4qBHK2hUaRPME0xCzAJ 12 | BgNVBAYTAkNOMRIwEAYDVQQIDAlTaGFuZyBIYWkxFDASBgNVBAoMC2V4YW1wbGUu 13 | Y29tMRQwEgYDVQQDDAtleGFtcGxlLmNvbYIJAMQooIBlaTnvMA4GA1UdDwEB/wQE 14 | AwIHgDATBgNVHSUEDDAKBggrBgEFBQcDATAKBggqgRzPVQGDdQNHADBEAiBnw6BM 15 | xCGIvFFuL3i+iYbNZbAhPiTb1kB4ZLJ3O3JumAIgXA2Rux0dW3r0FS8i+IS0CGDg 16 | fVOqRCWlxZBhMJvPeIk= 17 | -----END CERTIFICATE----- 18 | -------------------------------------------------------------------------------- /gmtls/gmcredentials/credentials_util_go18.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Suzhou Tongji Fintech Research Institute 2017 All Rights Reserved. 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | package gmcredentials 17 | 18 | import gmtls "github.com/tjfoc/gmsm/gmtls" 19 | 20 | // cloneTLSConfig returns a shallow clone of the exported 21 | // fields of cfg, ignoring the unexported sync.Once, which 22 | // contains a mutex and must not be copied. 23 | // 24 | // If cfg is nil, a new zero tls.Config is returned. 25 | func cloneTLSConfig(cfg *gmtls.Config) *gmtls.Config { 26 | if cfg == nil { 27 | return &gmtls.Config{} 28 | } 29 | 30 | return cfg.Clone() 31 | } 32 | -------------------------------------------------------------------------------- /sm4/padding/bloc_cryptor_test.go: -------------------------------------------------------------------------------- 1 | package padding 2 | 3 | import ( 4 | "bytes" 5 | "crypto/cipher" 6 | "crypto/rand" 7 | "fmt" 8 | "github.com/tjfoc/gmsm/sm4" 9 | "testing" 10 | ) 11 | 12 | func TestP7BlockDecrypt(t *testing.T) { 13 | src := bytes.Repeat([]byte{7}, 16) 14 | 15 | srcIn := bytes.NewBuffer(src) 16 | encOut := bytes.NewBuffer(make([]byte, 0, 1024)) 17 | 18 | key := make([]byte, 16) 19 | iv := make([]byte, 16) 20 | _, _ = rand.Read(key) 21 | _, _ = rand.Read(iv) 22 | fmt.Printf("key: %02X\n", key) 23 | fmt.Printf("iv : %02X\n", iv) 24 | block, err := sm4.NewCipher(key) 25 | if err != nil { 26 | t.Fatal(err) 27 | } 28 | encrypter := cipher.NewCBCEncrypter(block, iv) 29 | 30 | err = P7BlockEnc(encrypter, srcIn, encOut) 31 | if err != nil { 32 | t.Fatal(err) 33 | } 34 | fmt.Printf("原文: %02X\n", src) 35 | fmt.Printf("加密: %02X\n", encOut.Bytes()) 36 | 37 | decrypter := cipher.NewCBCDecrypter(block, iv) 38 | decOut := bytes.NewBuffer(make([]byte, 0, 1024)) 39 | err = P7BlockDecrypt(decrypter, encOut, decOut) 40 | if err != nil { 41 | t.Fatal(err) 42 | } 43 | 44 | fmt.Printf("解密: %02X\n", decOut.Bytes()) 45 | if !bytes.Equal(src, decOut.Bytes()) { 46 | t.Fatalf("实际解密结果: %02X, 期待结果: %02X", decOut.Bytes(), src) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /gmtls/websvr/certs/rsa_auth_cert.cer: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDUTCCAjmgAwIBAgIIAs4GXZbE1BcwDQYJKoZIhvcNAQELBQAwQjELMAkGA1UE 3 | BhMCQ04xDzANBgNVBAgMBua1meaxnzEPMA0GA1UEBwwG5p2t5beeMREwDwYDVQQK 4 | DAjmtYvor5VDQTAeFw0yMTA2MDMxNTA5NDVaFw0zMTA1MzAwNjU0NThaMDsxCzAJ 5 | BgNVBAYTAkNOMQ8wDQYDVQQIDAbmtZnmsZ8xDzANBgNVBAcMBuadreW3njEKMAgG 6 | A1UEAwwBKjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOk2VvN/B+UU 7 | voDdmxVZTA6ZQH/BZfDyACj3ssVCbNGwZllnjbb5GoLBA+3apQ6GNY5p5lzZoAI+ 8 | CR907g9Bjk4f9so9Nz97yDu4kGzFPfWQEqWAb3R/HA/IpXSyLWcCXcrYPbp8cFbT 9 | xMItDDO9RpwJ44u/npdk5TagiUJL/UdH3hDv9Ic8SvncDB45SP37aNzVrNjKi6Pe 10 | ZbDNSh2wVumW5Lvw+rKFLDKIRVnIAzisQrVrenDEDXHawV42J3FEjQ2q8ZIwVGzH 11 | WBfi4Pn6k3yd9GAg1HMCwapkoPNNcubAIo07YgcHJMSbAKIBG2p/RKBs3PsVrBxi 12 | e77iy5jTRp0CAwEAAaNSMFAwDgYDVR0PAQH/BAQDAgP4MB0GA1UdJQQWMBQGCCsG 13 | AQUFBwMBBggrBgEFBQcDAjAfBgNVHSMEGDAWgBTkg8zWkAOryxH1WmniX1Pc7zfk 14 | qTANBgkqhkiG9w0BAQsFAAOCAQEAgyoKfu6L3kaevwYb1LhlaUelSRLim6MTID3F 15 | +hxUF+LhORYSmZP92+YTIX7DZeWaXYfo14UTB9nVr5a27hz1M0GHRnI1aq/NeNiz 16 | jQNvRJmY6qgVyFCPCnanhqx3hHopU0ys4DXKnj4BJXmHvYeg8Ilq/ZYPY8Kiab0Q 17 | P7oOBsa68fY7/8mh8V1uo0FnfxupeCGsnA4V+xJ8d3EperhNoPlon8JlUyJMvITx 18 | /WJCH+ZeB+8OuUiK/XPATDrwdF3Ccwpm5CqzxRiLzZrygQF/b2QQ9B4VisY5DkAQ 19 | aXq5MlJxvF8DYmDb6EkvR5XwahElvYBX58Y/Ry+CtUwHkYt8qA== 20 | -----END CERTIFICATE----- 21 | -------------------------------------------------------------------------------- /gmtls/websvr/certs/RSA_CA.cer: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDaTCCAlGgAwIBAgIIAs4Fs2xsiCcwDQYJKoZIhvcNAQELBQAwQjELMAkGA1UE 3 | BhMCQ04xDzANBgNVBAgMBua1meaxnzEPMA0GA1UEBwwG5p2t5beeMREwDwYDVQQK 4 | DAjmtYvor5VDQTAeFw0yMTA1MzAwNjU0NThaFw0zMTA1MzAwNjU0NThaMEIxCzAJ 5 | BgNVBAYTAkNOMQ8wDQYDVQQIDAbmtZnmsZ8xDzANBgNVBAcMBuadreW3njERMA8G 6 | A1UECgwI5rWL6K+VQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDM 7 | iY3CcuyLC1Bh1weSpubbi6L7D7dFR1o8iynhC/bTVUvbM9zpTMU/54t9QiZo+aIQ 8 | 5q2wRwppW10eBL2WKYFNo6W9LcSqoDUSiiux8RXtU8EPGcJHbOQPcym7RZ1Q8StG 9 | bauXPVgbvuP7r3Q9QMVrQSDrN2Ek+D88mCqCwokSaRe0Ii6V7Sntx1De+geLAk3r 10 | gHUdanddLnfb2PEFOpnBoWStUJH5HnxDMaBxqN3P7JMmZmTHrcUr0wodKJTlHEr6 11 | DLBjP62K4u1Yoh5HD8+RRUVFfb7aXHetgReP5zAkmUhtY00n3KLF3g4UFcNxf1Lt 12 | snf/Va1WK6P+tReFG+jvAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB 13 | Af8EBTADAQH/MB0GA1UdDgQWBBTkg8zWkAOryxH1WmniX1Pc7zfkqTAfBgNVHSME 14 | GDAWgBTkg8zWkAOryxH1WmniX1Pc7zfkqTANBgkqhkiG9w0BAQsFAAOCAQEAxrxf 15 | mkWhMk0WikudPfQMmx3VIN0itxLMAeaV/56txMVu601hptcK76dgoVVMD4UWyaAI 16 | 8SZtLk+CpTSKGKBWbwkuop6E0kv9Ush2j5+cG8qj5AETsiwmUCUm/+YzuDqVXrgE 17 | cLLLYiF6r+p8/HM0+3l5uVw3bNLcUlZdUdIKsHhtfuytAGYz/DQnkgOCbgOx+j4k 18 | MRKK4iR+VWXYLksL0YleYD+JCd5HOTDEUnXjry0lqEAka4V0HMAHqv1+yxOzr/N6 19 | AUIy6TJfzTV1IFTv0BcFCq5DDzzK9Tzvmvbktb/XdPbi5dR53yCzITlBR4MXr5sy 20 | nggpRf1TWY7rlIw7GQ== 21 | -----END CERTIFICATE----- 22 | -------------------------------------------------------------------------------- /gmtls/websvr/certs/rsa_sign.cer: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDcDCCAligAwIBAgIIAs4Fs3BZK6cwDQYJKoZIhvcNAQELBQAwQjELMAkGA1UE 3 | BhMCQ04xDzANBgNVBAgMBua1meaxnzEPMA0GA1UEBwwG5p2t5beeMREwDwYDVQQK 4 | DAjmtYvor5VDQTAeFw0yMTA1MzAwNzIwNDJaFw0zMTA1MzAwNjU0NThaMFoxCzAJ 5 | BgNVBAYTAkNOMQ8wDQYDVQQIDAbmtZnmsZ8xDzANBgNVBAcMBuadreW3njEVMBMG 6 | A1UECgwM5rWL6K+V5YWs5Y+4MRIwEAYDVQQDEwlsb2NhbGhvc3QwggEiMA0GCSqG 7 | SIb3DQEBAQUAA4IBDwAwggEKAoIBAQC/FGo2/jbU3k5Ua+MkCkgcUvdQJMjg2dw/ 8 | zja0znHiGUlyfg2wWv9W5bXrgRGBAbSeGKSiMgePK43xpBGwoWM0TdqAOxQOqpQO 9 | wCgxShstsLz+3R2az0dza3wuVGlz9Pn/maSUBrrQuzyDwoY6XhQYHERfbvMzHQ2K 10 | ye02hdIdBGbgA7VtUJUAWlvjentIknUK+C3EKKOz0XgpGCVaud9U0t2QK3zpRTMW 11 | klJcIXHYUq7UUFBEq7gn3GPbzRe5LDp1sgYgemz1caRgUnTRL00R8jKqUUqvHdOW 12 | jrYk9c4vNmNZeVLnNpWNXM8/SY3RLXOhS1ncrJK33VFJsZPjBqLLAgMBAAGjUjBQ 13 | MA4GA1UdDwEB/wQEAwID+DAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw 14 | HwYDVR0jBBgwFoAU5IPM1pADq8sR9Vpp4l9T3O835KkwDQYJKoZIhvcNAQELBQAD 15 | ggEBAIleQQd1YgNS/+7gCJYsTi1VGqsUKpCShSe+DFUbOnJgKaGNAcVERZkYspz4 16 | k9dxcM0IOabxtQWNj/5sfeIwzar0btMo8J4myrgM9iT3f7LXCIUx6cSFZimlZ0JX 17 | PS9FEd/8/YhPhDuo7r0GK9OBqe+77sa7jhYLHZyhmtsDGONjivANpZbLu4t2GHjh 18 | 300adouQF6zYMkg+49lrSf7QLqgEE5JJM8CkbaY3O7FflS7kEHCzCd/cfqKacvWb 19 | 4Kl0T4TezbWbwLUY1pY8Ik9aHVsghm0tUb6e1QD5cDcN7EyhSnFug1TcG6YbhyZC 20 | lwciqUnSvOPYbVlosRFmQ2kUp9U= 21 | -----END CERTIFICATE----- 22 | -------------------------------------------------------------------------------- /sm4/padding/bloc_cryptor.go: -------------------------------------------------------------------------------- 1 | package padding 2 | 3 | import ( 4 | "crypto/cipher" 5 | "io" 6 | ) 7 | 8 | // P7BlockDecrypt 解密密文,并去除PKCS#7填充 9 | // decrypter: 块解密器 10 | // in: 密文输入流 11 | // out: 明文输出流 12 | func P7BlockDecrypt(decrypter cipher.BlockMode, in io.Reader, out io.Writer) error { 13 | bufIn := make([]byte, 1024) 14 | bufOut := make([]byte, 1024) 15 | p7Out := NewPKCS7PaddingWriter(out, decrypter.BlockSize()) 16 | for { 17 | n, err := in.Read(bufIn) 18 | if err != nil && err != io.EOF { 19 | return err 20 | } 21 | if n == 0 { 22 | break 23 | } 24 | decrypter.CryptBlocks(bufOut, bufIn[:n]) 25 | _, err = p7Out.Write(bufOut[:n]) 26 | if err != nil { 27 | return err 28 | } 29 | } 30 | return p7Out.Final() 31 | } 32 | 33 | // P7BlockEnc 以PKCS#7填充模式填充原文,并加密输出 34 | // encrypter: 块加密器 35 | // in: 明文输入流 36 | // out: 密文输出流 37 | func P7BlockEnc(encrypter cipher.BlockMode, in io.Reader, out io.Writer) error { 38 | bufIn := make([]byte, 1024) 39 | bufOut := make([]byte, 1024) 40 | p7In := NewPKCS7PaddingReader(in, encrypter.BlockSize()) 41 | for { 42 | n, err := p7In.Read(bufIn) 43 | if err != nil && err != io.EOF { 44 | return err 45 | } 46 | if n == 0 { 47 | break 48 | } 49 | encrypter.CryptBlocks(bufOut, bufIn[:n]) 50 | _, err = out.Write(bufOut[:n]) 51 | if err != nil { 52 | return err 53 | } 54 | } 55 | return nil 56 | } 57 | -------------------------------------------------------------------------------- /sm2/utils.go: -------------------------------------------------------------------------------- 1 | package sm2 2 | 3 | import ( 4 | "encoding/asn1" 5 | "math/big" 6 | ) 7 | 8 | func Decompress(a []byte) *PublicKey { 9 | var aa, xx, xx3 sm2P256FieldElement 10 | 11 | P256Sm2() 12 | x := new(big.Int).SetBytes(a[1:]) 13 | curve := sm2P256 14 | sm2P256FromBig(&xx, x) 15 | sm2P256Square(&xx3, &xx) // x3 = x ^ 2 16 | sm2P256Mul(&xx3, &xx3, &xx) // x3 = x ^ 2 * x 17 | sm2P256Mul(&aa, &curve.a, &xx) // a = a * x 18 | sm2P256Add(&xx3, &xx3, &aa) 19 | sm2P256Add(&xx3, &xx3, &curve.b) 20 | 21 | y2 := sm2P256ToBig(&xx3) 22 | y := new(big.Int).ModSqrt(y2, sm2P256.P) 23 | if getLastBit(y) != uint(a[0]) { 24 | y.Sub(sm2P256.P, y) 25 | } 26 | return &PublicKey{ 27 | Curve: P256Sm2(), 28 | X: x, 29 | Y: y, 30 | } 31 | } 32 | 33 | func Compress(a *PublicKey) []byte { 34 | buf := []byte{} 35 | yp := getLastBit(a.Y) 36 | buf = append(buf, a.X.Bytes()...) 37 | if n := len(a.X.Bytes()); n < 32 { 38 | buf = append(zeroByteSlice()[:(32-n)], buf...) 39 | } 40 | buf = append([]byte{byte(yp)}, buf...) 41 | return buf 42 | } 43 | 44 | type sm2Signature struct { 45 | R, S *big.Int 46 | } 47 | 48 | func SignDigitToSignData(r, s *big.Int) ([]byte, error) { 49 | return asn1.Marshal(sm2Signature{r, s}) 50 | } 51 | 52 | func SignDataToSignDigit(sign []byte) (*big.Int, *big.Int, error) { 53 | var sm2Sign sm2Signature 54 | 55 | _, err := asn1.Unmarshal(sign, &sm2Sign) 56 | if err != nil { 57 | return nil, nil, err 58 | } 59 | return sm2Sign.R, sm2Sign.S, nil 60 | } 61 | -------------------------------------------------------------------------------- /pkcs12/mac.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package pkcs12 6 | 7 | import ( 8 | "crypto/hmac" 9 | "crypto/sha1" 10 | "crypto/x509/pkix" 11 | "encoding/asn1" 12 | ) 13 | 14 | type macData struct { 15 | Mac digestInfo 16 | MacSalt []byte 17 | Iterations int `asn1:"optional,default:1"` 18 | } 19 | 20 | // from PKCS#7: 21 | type digestInfo struct { 22 | Algorithm pkix.AlgorithmIdentifier 23 | Digest []byte 24 | } 25 | 26 | var ( 27 | oidSHA1 = asn1.ObjectIdentifier([]int{1, 3, 14, 3, 2, 26}) 28 | ) 29 | 30 | func verifyMac(macData *macData, message, password []byte) error { 31 | if !macData.Mac.Algorithm.Algorithm.Equal(oidSHA1) { 32 | return NotImplementedError("unknown digest algorithm: " + macData.Mac.Algorithm.Algorithm.String()) 33 | } 34 | 35 | key := pbkdf(sha1Sum, 20, 64, macData.MacSalt, password, macData.Iterations, 3, 20) 36 | 37 | mac := hmac.New(sha1.New, key) 38 | mac.Write(message) 39 | expectedMAC := mac.Sum(nil) 40 | 41 | if !hmac.Equal(macData.Mac.Digest, expectedMAC) { 42 | return ErrIncorrectPassword 43 | } 44 | return nil 45 | } 46 | 47 | func computeMac(macData *macData, message, password []byte) error { 48 | if !macData.Mac.Algorithm.Algorithm.Equal(oidSHA1) { 49 | return NotImplementedError("unknown digest algorithm: " + macData.Mac.Algorithm.Algorithm.String()) 50 | } 51 | 52 | key := pbkdf(sha1Sum, 20, 64, macData.MacSalt, password, macData.Iterations, 3, 20) 53 | 54 | mac := hmac.New(sha1.New, key) 55 | mac.Write(message) 56 | macData.Mac.Digest = mac.Sum(nil) 57 | 58 | return nil 59 | } 60 | -------------------------------------------------------------------------------- /pkcs12/bmp-string.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package pkcs12 6 | 7 | import ( 8 | "errors" 9 | "unicode/utf16" 10 | ) 11 | 12 | // bmpString returns s encoded in UCS-2 with a zero terminator. 13 | func bmpString(s string) ([]byte, error) { 14 | // References: 15 | // https://tools.ietf.org/html/rfc7292#appendix-B.1 16 | // http://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_Multilingual_Plane 17 | // - non-BMP characters are encoded in UTF 16 by using a surrogate pair of 16-bit codes 18 | // EncodeRune returns 0xfffd if the rune does not need special encoding 19 | // - the above RFC provides the info that BMPStrings are NULL terminated. 20 | 21 | ret := make([]byte, 0, 2*len(s)+2) 22 | 23 | for _, r := range s { 24 | if t, _ := utf16.EncodeRune(r); t != 0xfffd { 25 | return nil, errors.New("go-pkcs12: string contains characters that cannot be encoded in UCS-2") 26 | } 27 | ret = append(ret, byte(r/256), byte(r%256)) 28 | } 29 | 30 | return append(ret, 0, 0), nil 31 | } 32 | 33 | func decodeBMPString(bmpString []byte) (string, error) { 34 | if len(bmpString)%2 != 0 { 35 | return "", errors.New("go-pkcs12: odd-length BMP string") 36 | } 37 | 38 | // strip terminator if present 39 | if l := len(bmpString); l >= 2 && bmpString[l-1] == 0 && bmpString[l-2] == 0 { 40 | bmpString = bmpString[:l-2] 41 | } 42 | 43 | s := make([]uint16, 0, len(bmpString)/2) 44 | for len(bmpString) > 0 { 45 | s = append(s, uint16(bmpString[0])<<8+uint16(bmpString[1])) 46 | bmpString = bmpString[2:] 47 | } 48 | 49 | return string(utf16.Decode(s)), nil 50 | } 51 | -------------------------------------------------------------------------------- /sm3/sm3_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Suzhou Tongji Fintech Research Institute 2017 All Rights Reserved. 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | package sm3 17 | 18 | import ( 19 | "fmt" 20 | "io/ioutil" 21 | "os" 22 | "testing" 23 | ) 24 | 25 | func byteToString(b []byte) string { 26 | ret := "" 27 | for i := 0; i < len(b); i++ { 28 | ret += fmt.Sprintf("%02x", b[i]) 29 | } 30 | fmt.Println("ret = ", ret) 31 | return ret 32 | } 33 | func TestSm3(t *testing.T) { 34 | msg := []byte("test") 35 | err := ioutil.WriteFile("ifile", msg, os.FileMode(0644)) // 生成测试文件 36 | if err != nil { 37 | t.Fatal(err) 38 | } 39 | msg, err = ioutil.ReadFile("ifile") 40 | if err != nil { 41 | t.Fatal(err) 42 | } 43 | hw := New() 44 | hw.Write(msg) 45 | hash := hw.Sum(nil) 46 | fmt.Println(hash) 47 | fmt.Printf("hash = %d\n", len(hash)) 48 | fmt.Printf("%s\n", byteToString(hash)) 49 | hash1 := Sm3Sum(msg) 50 | fmt.Println(hash1) 51 | fmt.Printf("%s\n", byteToString(hash1)) 52 | 53 | } 54 | 55 | func BenchmarkSm3(t *testing.B) { 56 | t.ReportAllocs() 57 | msg := []byte("test") 58 | hw := New() 59 | for i := 0; i < t.N; i++ { 60 | 61 | hw.Sum(nil) 62 | Sm3Sum(msg) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /gmtls/websvr/certs/rsa_auth_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEogIBAAKCAQEA6TZW838H5RS+gN2bFVlMDplAf8Fl8PIAKPeyxUJs0bBmWWeN 3 | tvkagsED7dqlDoY1jmnmXNmgAj4JH3TuD0GOTh/2yj03P3vIO7iQbMU99ZASpYBv 4 | dH8cD8ildLItZwJdytg9unxwVtPEwi0MM71GnAnji7+el2TlNqCJQkv9R0feEO/0 5 | hzxK+dwMHjlI/fto3NWs2MqLo95lsM1KHbBW6Zbku/D6soUsMohFWcgDOKxCtWt6 6 | cMQNcdrBXjYncUSNDarxkjBUbMdYF+Lg+fqTfJ30YCDUcwLBqmSg801y5sAijTti 7 | BwckxJsAogEban9EoGzc+xWsHGJ7vuLLmNNGnQIDAQABAoIBAF2ev9cuJrgy1Ksc 8 | yzYNy/eMVBU1STwpmiDYFv8TRGYFP4EijgRnCdp1q6Mfg+VJwVQzdRPPFWnxB26G 9 | XU7ojT0VndfgLT6h7Wb0F55irBXZSXMBFT0aDeTUMn+fS5SvoYFdv6IOdHaWusUM 10 | mnpmwGLBoYQnX339NfrxBUkFAl9LWUrw3Y+ON9R6uEeSMntD84L4R9R+84S5BeTr 11 | 6zb/XoT4YvD6RS8HOB7XBCGlLTwds+a4zyQnuCCHbKIES9lxItF0QbprG5J+Q7gp 12 | lebi/zXLWbUg22S3mzTmP3R8l0LWwKhyPnBh8onNf/Nroa68r9FlEFSglj/5MAvJ 13 | pAD6/80CgYEA975QPGmW6mxBxUr3OVZTKmTVGHonEb/qVr489zgnruWwbY7Y344V 14 | qw2nY+EiT2ftGsZmb/LZ3fEaSdmKYb1rDS9Jslfd3E1yUygFFtwqiGqWEp8LDDvU 15 | UgqDvMdoDaGIKcl0EyeWOjCi073B2MSC9prKY9MuxHpOfZ7f4aN7GbsCgYEA8PwM 16 | zZZCAWRFlasxYe59uU63vSmDGkMcy0W494IrfcqPLIoin4Xkdrjb1LVI6dYb27/W 17 | 2gFMKMlWCHCvaayFzgmwjIK8+r+nUWAuxCWljxOaB3wIKf3q1sNVAITfFTuV1k6d 18 | Svl55fpYAPqDu6JLSqoIZK+Vw2amTOnJSrZoT4cCgYBuZ5uuMIgW1EPDPpNKNBQ/ 19 | 8kuc6uL6YAJ4wbK9oYLdyHKFgIFZryIs5prQQgZeSLw7kGsaPKmm5MmIW6/1uso4 20 | R/iZx9qRUNpAALez5k32GTnj9oif3RHTtefbeyn92RyrMqHN33htWjtWDVyT049h 21 | gr3rGrPez3qnNOQk1AwJ/QKBgGeOuOXEE1tLvsdhiNgfx7FRTY4hf7BSdNY5gRID 22 | wzLMUBiAx/4raJFIQVe4C7xJATG+z9JhSlwgoTMBUbAkrl9rNI49RH6wy3Mh1Rb/ 23 | YpUIhGGBAHUjI77ks+uELeWO9IXixJ9KdALLQPQys1d3l8lfJjo2ZjJRM1fMA29y 24 | 0YKTAoGAA7adLMc8uePn6Dclw/MQ291t3JWYKOuZ5bM4BfwMf+Xr5XHuIylNaxgJ 25 | JyIkZcrnEpIjKwtwCBUf3fJ2I39d7Euhdss7yS+YVrvuQSINtoKRmZ45PKP0MKNf 26 | +YyctbsNPGmbzK93WBijRefdAIvyGG29FlXwnKP9A0tBXM7yx1o= 27 | -----END PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /gmtls/websvr/certs/rsa_sign_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEowIBAAKCAQEAvxRqNv421N5OVGvjJApIHFL3UCTI4NncP842tM5x4hlJcn4N 3 | sFr/VuW164ERgQG0nhikojIHjyuN8aQRsKFjNE3agDsUDqqUDsAoMUobLbC8/t0d 4 | ms9Hc2t8LlRpc/T5/5mklAa60Ls8g8KGOl4UGBxEX27zMx0NisntNoXSHQRm4AO1 5 | bVCVAFpb43p7SJJ1CvgtxCijs9F4KRglWrnfVNLdkCt86UUzFpJSXCFx2FKu1FBQ 6 | RKu4J9xj280XuSw6dbIGIHps9XGkYFJ00S9NEfIyqlFKrx3Tlo62JPXOLzZjWXlS 7 | 5zaVjVzPP0mN0S1zoUtZ3KySt91RSbGT4waiywIDAQABAoIBAHON1AH30I8A9ZvG 8 | NvHnqd4/KkL0S+r2tWR8v8auBl72bd1ob7zT+xDBEDggsMY0ktb9DirsWHfznf6g 9 | +vW3U7gg0N+1WpbX/3vAJ05Pg4opFNKIQ8wISCx7tviJodA3OSyi7M18GGP8p0cD 10 | T4tis4I1LgAMp9SkYDkrjmHnob5biilhdAGseJWjyKMxBc1sqMQVy+Gia49guU0J 11 | fnEOu1jT6P/ZB7P7wyiFEVJKYvU/iMQ2rCiBlBKmAa4ZuV/rMLs7/twwiD1EtMNc 12 | bpwoNeEI7XC+HCwpYNecscIxhs3zcjqasc93B7Sn0MHhdxz2aU6TH2BSA+S1zfzm 13 | +fcgS1kCgYEA/Tl3WERs2VjNW01c5yQ5fz3yKhqHgBZ9KODasLdX4/4b18ZRiQdI 14 | VRCMSjhp0IryYgkH78X6fKIdzA276MNpAK3mcCu6dI6d8ige55A4cwyS3P23b2Ft 15 | VB9TAHUJ+5F3fXHAjXYBzMsDNCkZqedPRj18+GMyHfMV05eqzEzR/p8CgYEAwSyS 16 | 9NDir1lQVcjDy4IF8cjsuFT3R1KbUy29MOCBcTd4RaB/vTEs4nCZlpb9wBBJqQBu 17 | 5CCH5wOxc+WvoEicpzrcwqWBTmUngulVHumub8VeahTHZsbPXDlc6hXg+kXimo0S 18 | rNGHGz76aBEgxpD8KnoRiBXL5KUXkYVSeFtT6FUCgYBlwRTbDEvtHskOekztuNm9 19 | 7seD8bsnVmIe7hQS1OnlfPP1RgT3mkyPmiG1pWun2F3D1TsyN40LTh3JJG+w/e0Q 20 | z9B8nKXFNpXze/nHNWXpnVDaqr1ubWkAV8IDugQz6eVpLC+i6Juajq2P5UAhzQhH 21 | AmhYa4v1CvxnVVfV1ry/owKBgHJrFnhPqZU3D7BgBCjsUN0Pp7bfDMCAG2Q/OUpU 22 | EBehRWnoUQEcuXs+OprJwG8ctqSVjxksc5LPyzHcoBQOLkuXP99C7L4kiCywTCzN 23 | OPcXLn8i46DqrTPw/ing36sd7cShPqiCSsZGnUc6rfEvO01llDDIyEYby0P0dg63 24 | +ZEpAoGBAPQQY2ojWp8smOpQhtkqPjeDb2rjSGoniBz3mapFv4WuPmpQhRKh/dcu 25 | gCIHmXOAEz8nLCKWF+CsKpvLIuO+nyT2XadPuz3nAJM6VwVZ+wrQUEI6tP4DcfqB 26 | SDcVFeEKFw+nZGMFfTm3g5/eFraRjSBK5a5immGBMJCQQanniN7B 27 | -----END PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /gmtls/websvr/certs/RSA_CA_KEY.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEpAIBAAKCAQEAzImNwnLsiwtQYdcHkqbm24ui+w+3RUdaPIsp4Qv201VL2zPc 3 | 6UzFP+eLfUImaPmiEOatsEcKaVtdHgS9limBTaOlvS3EqqA1EoorsfEV7VPBDxnC 4 | R2zkD3Mpu0WdUPErRm2rlz1YG77j+690PUDFa0Eg6zdhJPg/PJgqgsKJEmkXtCIu 5 | le0p7cdQ3voHiwJN64B1HWp3XS5329jxBTqZwaFkrVCR+R58QzGgcajdz+yTJmZk 6 | x63FK9MKHSiU5RxK+gywYz+tiuLtWKIeRw/PkUVFRX2+2lx3rYEXj+cwJJlIbWNN 7 | J9yixd4OFBXDcX9S7bJ3/1WtViuj/rUXhRvo7wIDAQABAoIBAEJngiOYJh26TZ2G 8 | L0o4b4jlm8NAxfJzCOPRFoae2MKh1Z/UBaukpgFqTgobmNbJ/QjZq5goaEPuSpv9 9 | VAPVc8peD+gMXOY8Xx6mxyrdJ45Ge85IQZ/oxV4SuIC5SCrIMZGK94OBggJ4BhJn 10 | Uyizx6Rbn7Fd6GcVRYqJqHuNZu0XprculGZ58CA//EJejDm0QZc8lqFlis5WCJ/G 11 | GMV1xMNx/QhU7ObbzVGfIUeDyYCsO7F3SxWbo9cyToQi/14MeI/kLhSp9CPv2PSL 12 | ezkSazVrRxNqOJBzlTncA+z0p+RLdfvkNB82CAtJdnN94VF5H1/dePkn4HhT9hz5 13 | vP55HZECgYEA8QNqw7qwH6jfRpaAcJ8DP8MPzZVPF7rliK4buQDcE/5LzIP/5BhK 14 | dCT+vKYHcPGF3IqsQ6rZDZ4aUvlzdXi8yolz6NNDgEGYYiQH0qNFY1DnR+YnqtuS 15 | o1+LmZXJkuRk/6w2/Fd+EDK+7SLLQLKDGb+bmReDvW3vye2DbN/mSicCgYEA2UF9 16 | wRA45+2gaK4cEkrovq6j6U8+IYPuQFXVFVKhILGN69/l1ZLamVMGX5tMUwfwJdh8 17 | 2Ewqz5tpdBrrCwdnhQHugZl9YFzLej98eLREOqiOcqAvFVjFsbtfe4jwFn7ciHuO 18 | Fe//xWrI9dVQLhL/cAuJMtTlWVCnAGCIhjj+j/kCgYEAsSVb0eVkEsEi61UvrpeR 19 | 4cnT0b2O1thOYbnnMoHJQQDGYdobuWGJR/jxK2O1UHSVeVaL62imBPZSTu5+yLcn 20 | vI5vHZA6qwiLoobtIQtUsv0CIbyvJ0wgaeiOSSLpeAhbm/jOqYb9Z5aE8vOCBVmw 21 | Nrq4+TtpX1Bw0TC8Ssf/Ej0CgYAnbA7ZnYv16dSVqiJF33nkP+RWTZ7EjiAJZInJ 22 | 2LiMKivKhVI7Mu6fq8UYTCHJX0NgWqwsw4VxLo4wF0JXOfy60eLpeWSau7vgbuyz 23 | KmLHEhbnDdH9WaJl4c4tqGeIbXSu/1yE9ou+0uWsVgy6j4/yUOWQZ7lGP7BODTY4 24 | xNbMYQKBgQCn3AhkE2di4XHdKZOr3aSW6yJovZl+7bF1/xiMuOh5Noz7h6RwVGa4 25 | 2ZJnRyyV3oeOIftkBNls42LPpqo1O2Y7vOdxLtdh9DLJbVAUgobvIufpJ6VSUhmP 26 | THNdL0/ciJ3vP9zLtcVVYR/2IyI+lMbnyhD8BNvFzbblK1NUSJiStQ== 27 | -----END PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /sm4/padding/pkcs7_padding_io_test.go: -------------------------------------------------------------------------------- 1 | package padding 2 | 3 | import ( 4 | "bytes" 5 | "io" 6 | "testing" 7 | ) 8 | 9 | // 测试P7填充Reader 10 | func TestPaddingFileReader_Read(t *testing.T) { 11 | srcIn := bytes.NewBuffer(bytes.Repeat([]byte{'A'}, 16)) 12 | p := NewPKCS7PaddingReader(srcIn, 16) 13 | 14 | tests := []struct { 15 | name string 16 | buf []byte 17 | want int 18 | wantErr error 19 | }{ 20 | {"读取文件 1B", make([]byte, 1), 1, nil}, 21 | {"交叉读取 15B 文件 1B", make([]byte, 16), 16, nil}, 22 | {"填充读取 3B", make([]byte, 3), 3, nil}, 23 | {"超过填充读取 16B", make([]byte, 16), 12, nil}, 24 | {"文件结束 16B", make([]byte, 16), 0, io.EOF}, 25 | } 26 | for _, tt := range tests { 27 | t.Run(tt.name, func(t *testing.T) { 28 | got, err := p.Read(tt.buf) 29 | if err != tt.wantErr { 30 | t.Errorf("Read() error = %v, wantErr %v", err, tt.wantErr) 31 | return 32 | } 33 | if got != tt.want { 34 | t.Errorf("Read() 读取到了 = %v, 但是需要 %v", got, tt.want) 35 | } 36 | }) 37 | } 38 | } 39 | 40 | // 测试P7填充Writer 41 | func TestPKCS7PaddingWriter_Write(t *testing.T) { 42 | src := []byte{ 43 | 0, 1, 2, 3, 4, 5, 6, 7, 44 | } 45 | paddedSrc := append(src, bytes.Repeat([]byte{0x08}, 8)...) 46 | reader := bytes.NewReader(paddedSrc) 47 | out := bytes.NewBuffer(make([]byte, 0, 64)) 48 | writer := NewPKCS7PaddingWriter(out, 8) 49 | 50 | for { 51 | buf := make([]byte, 3) 52 | n, err := reader.Read(buf) 53 | if err != nil && err != io.EOF { 54 | t.Fatal(err) 55 | } 56 | if n == 0 { 57 | break 58 | } 59 | _, err = writer.Write(buf[:n]) 60 | if err != nil { 61 | t.Fatal(err) 62 | } 63 | } 64 | err := writer.Final() 65 | if err != nil { 66 | t.Fatal(err) 67 | } 68 | 69 | if !bytes.Equal(out.Bytes(), src) { 70 | t.Fatalf("去除填充后实际为 %02X,期待去除填充之后的结果为 %02X", out.Bytes(), src) 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # gmsm 3 | GM SM2/3/4 library based on Golang 4 | ======= 5 | 6 | [![Build Status](https://travis-ci.com/tjfoc/gmsm.svg?branch=master)](https://travis-ci.com/github/tjfoc/gmsm) 7 | 8 | 9 | ## Feature 10 | gmsm包含以下主要功能 11 | 12 | SM2: 国密椭圆曲线算法库 13 | . 支持Generate Key, Sign, Verify基础操作 14 | . 支持加密和不加密的pem文件格式(加密方法参见RFC5958, 具体实现参加代码) 15 | . 支持证书的生成,证书的读写(接口兼容rsa和ecdsa的证书) 16 | . 支持证书链的操作(接口兼容rsa和ecdsa) 17 | . 支持crypto.Signer接口 18 | 19 | SM3: 国密hash算法库 20 | . 支持基础的sm3Sum操作 21 | . 支持hash.Hash接口 22 | 23 | SM4: 国密分组密码算法库 24 | . 支持Generate Key, Encrypt, Decrypt基础操作 25 | . 提供Cipher.Block接口 26 | . 支持加密和不加密的pem文件格式(加密方法为pem block加密, 具体函数为x509.EncryptPEMBlock) 27 | 28 | ## [Usage 使用说明](./API使用说明.md) 29 | 30 | ## Communication 31 | tjfoc国密交流 32 | 33 | [![Join the chat at https://gitter.im/tjfoc/gmsm](https://badges.gitter.im/tjfoc/gmsm.svg)](https://gitter.im/tjfoc/gmsm?utm_source=badge&utm_medium=badge&utm_campaign=-badge&utm_content=badge) 34 | 35 | 36 | - 如果你对国密算法开源技术及应用感兴趣,欢迎添加“苏州同济区块链研究院·小助手“微信,回复“国密算法进群”,加入“同济区块链国密算法交流群”。微信二维码如下: 37 | ![微信二维码](https://github.com/tjfoc/wutongchian-public/blob/master/wutongchain.png) 38 | 39 | - 发送邮件到tj@wutongchain.com 40 | 41 | 42 | ## License 43 | 版权所有 苏州同济区块链研究院有限公司(http://www.wutongchain.com/) 44 | 45 | Copyright 2017- Suzhou Tongji Fintech Research Institute. All Rights Reserved. 46 | Licensed under the Apache License, Version 2.0 (the "License"); 47 | 48 | you may not use this file except in compliance with the License. 49 | You may obtain a copy of the License at 50 | http://www.apache.org/licenses/LICENSE-2.0 51 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 52 | 53 | See the License for the specific language governing permissions and limitations under the License. 54 | ======= 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /sm4/sm4_gcm_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Hyperledger-TWGC All Rights Reserved. 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | 15 | writed by Zhiwei Yan, 2020 Oct 16 | */ 17 | 18 | package sm4 19 | 20 | import ( 21 | "bytes" 22 | "fmt" 23 | "testing" 24 | ) 25 | 26 | 27 | func TestSM4GCM(t *testing.T){ 28 | key := []byte("1234567890abcdef") 29 | data := []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10} 30 | IV :=make([]byte,BlockSize) 31 | testA:=[][]byte{ // the length of the A can be random 32 | []byte{}, 33 | []byte{0x01, 0x23, 0x45, 0x67, 0x89}, 34 | []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10}, 35 | } 36 | for _,A:=range testA{ 37 | gcmMsg,T,err:=Sm4GCM(key,IV,data,A,true) 38 | if err !=nil{ 39 | t.Errorf("sm4 enc error:%s", err) 40 | } 41 | fmt.Printf("gcmMsg = %x\n", gcmMsg) 42 | gcmDec,T_,err:=Sm4GCM(key,IV,gcmMsg,A,false) 43 | if err != nil{ 44 | t.Errorf("sm4 dec error:%s", err) 45 | } 46 | fmt.Printf("gcmDec = %x\n", gcmDec) 47 | if bytes.Compare(T,T_)==0{ 48 | fmt.Println("authentication successed") 49 | } 50 | //Failed Test : if we input the different A , that will be a falied result. 51 | A= []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd} 52 | gcmDec,T_,err=Sm4GCM(key,IV,gcmMsg,A ,false) 53 | if err != nil{ 54 | t.Errorf("sm4 dec error:%s", err) 55 | } 56 | if bytes.Compare(T,T_)!=0{ 57 | fmt.Println("authentication failed") 58 | } 59 | } 60 | 61 | } -------------------------------------------------------------------------------- /sm4/padding/README.md: -------------------------------------------------------------------------------- 1 | # PCSK#7 填充读写流 2 | 3 | 直接使用分块加密,往往需要手动完成填充和去填充的过程。流程较为固定,但是比较繁琐,对于文件和流的处理,不是很友好。 4 | 5 | PKCS#7填充和去除填充: 6 | 7 | - `padding.PKCS7PaddingReader` 写入结束是添加填充 8 | - `padding.PKCS7PaddingWriter` 读取时去除填充 9 | 10 | 封装的填充模式加密: 11 | 12 | - `padding.P7BlockEnc` 13 | - `padding.P7BlockDecrypt` 14 | 15 | 以上方法简化了,对文件和流类型的加密解密过程。 16 | 17 | ## 带填充的模式加密和解密 18 | 19 | > 流:实现了 `io.Writer`、`io.Reader`接口的类型。 20 | 21 | 流的SM4分块CBC模式加密: 22 | 23 | ```go 24 | func main() { 25 | src := bytes.Repeat([]byte{7}, 16) 26 | srcIn := bytes.NewBuffer(src) 27 | encOut := bytes.NewBuffer(make([]byte, 0, 1024)) 28 | 29 | key := make([]byte, 16) 30 | iv := make([]byte, 16) 31 | _, _ = rand.Read(key) 32 | _, _ = rand.Read(iv) 33 | fmt.Printf("key: %02X\n", key) 34 | fmt.Printf("iv : %02X\n", iv) 35 | block, err := sm4.NewCipher(key) 36 | if err != nil { 37 | panic(err) 38 | } 39 | encrypter := cipher.NewCBCEncrypter(block, iv) 40 | // P7填充的CBC加密 41 | err = padding.P7BlockEnc(encrypter, srcIn, encOut) 42 | if err != nil { 43 | panic(err) 44 | } 45 | fmt.Printf("原文: %02X\n", src) 46 | fmt.Printf("加密: %02X\n", encOut.Bytes()) 47 | } 48 | ``` 49 | 50 | 流的SM4分块CBC模式解密: 51 | 52 | ```go 53 | func main() { 54 | /** 55 | key: 4C9CA3D17263F6F558D65ADB561465BD 56 | iv : 221908D1C4BD730BEB011319D1368E49 57 | 原文: 07070707070707070707070707070707 58 | 加密: 310CA2472DCE15CCC58E1BE69B876002F443556CCFB86B1BA0341B6BFBED4C1A 59 | */ 60 | encOut := bytes.NewBuffer(make([]byte, 0, 1024)) 61 | key,_ := hex.DecodeString("4C9CA3D17263F6F558D65ADB561465BD") 62 | iv,_ := hex.DecodeString("221908D1C4BD730BEB011319D1368E49") 63 | block, err := sm4.NewCipher(key) 64 | if err != nil { 65 | panic(err) 66 | } 67 | ciphertext, _ := hex.DecodeString("310CA2472DCE15CCC58E1BE69B876002F443556CCFB86B1BA0341B6BFBED4C1A") 68 | cipherReader := bytes.NewReader(ciphertext) 69 | decrypter := cipher.NewCBCDecrypter(block, iv) 70 | decOut := bytes.NewBuffer(make([]byte, 0, 1024)) 71 | err = padding.P7BlockDecrypt(decrypter, ciphertext, decOut) 72 | if err != nil { 73 | panic(err) 74 | } 75 | 76 | fmt.Printf("解密: %02X\n", decOut.Bytes()) 77 | } 78 | ``` 79 | 80 | ## PKCS#7填充 81 | 82 | 见测试用例: [pkcs7_padding_io_test.go](./pkcs7_padding_io_test.go) 83 | -------------------------------------------------------------------------------- /gmtls/simple_round_trip.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Suzhou Tongji Fintech Research Institute 2017 All Rights Reserved. 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | package gmtls 17 | 18 | import ( 19 | "bufio" 20 | "fmt" 21 | "io" 22 | "net" 23 | "net/http" 24 | "sync" 25 | ) 26 | 27 | // SimpleRoundTripper 简单的单次HTTP/HTTPS(国密) 连接往返器 28 | // 每次建立新的连接 29 | type SimpleRoundTripper struct { 30 | lock sync.Mutex 31 | tlsConfig *Config 32 | } 33 | 34 | func NewSimpleRoundTripper(cfg *Config) *SimpleRoundTripper { 35 | return &SimpleRoundTripper{tlsConfig: cfg} 36 | } 37 | 38 | func (s *SimpleRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { 39 | // 加锁保证线程安全 40 | s.lock.Lock() 41 | defer s.lock.Unlock() 42 | 43 | scheme := req.URL.Scheme 44 | isHTTP := scheme == "http" || scheme == "https" 45 | if !isHTTP { 46 | return nil, fmt.Errorf("仅支持http/https协议") 47 | } 48 | 49 | // 获取主机名 和 端口 50 | hostname := req.URL.Hostname() 51 | port := req.URL.Port() 52 | address := net.JoinHostPort(hostname, port) 53 | 54 | var conn io.ReadWriteCloser 55 | var err error 56 | // 根据协议建立连接 57 | if scheme == "http" { 58 | // HTTP 协议建立TCP连接 59 | conn, err = net.Dial("tcp", address) 60 | if err != nil { 61 | return nil, err 62 | } 63 | } else { 64 | // HTTPS 协议建立TLS连接 65 | conn, err = Dial("tcp", address, s.tlsConfig) 66 | if err != nil { 67 | return nil, err 68 | } 69 | } 70 | defer conn.Close() 71 | 72 | // 把请求写入连接中,发起请求 73 | err = req.Write(conn) 74 | if err != nil { 75 | return nil, err 76 | } 77 | // 从连接中读取 78 | response, err := http.ReadResponse(bufio.NewReader(conn), req) 79 | if err != nil { 80 | return nil, err 81 | } 82 | // 协议升级时,替换Body实现 83 | if response.StatusCode == http.StatusSwitchingProtocols { 84 | response.Body = conn 85 | } 86 | return response, nil 87 | } 88 | -------------------------------------------------------------------------------- /pkcs12/pkcs12_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package pkcs12 6 | 7 | import ( 8 | "encoding/base64" 9 | "fmt" 10 | "io/ioutil" 11 | "os" 12 | "testing" 13 | 14 | "github.com/tjfoc/gmsm/sm2" 15 | "github.com/tjfoc/gmsm/x509" 16 | ) 17 | 18 | func Test_P12Encrypt(t *testing.T) { 19 | str := "MIICiTCCAi6gAwIBAgIIICAEFwACVjAwCgYIKoEcz1UBg3UwdjEcMBoGA1UEAwwTU21hcnRDQV9UZXN0X1NNMl9DQTEVMBMGA1UECwwMU21hcnRDQV9UZXN0MRAwDgYDVQQKDAdTbWFydENBMQ8wDQYDVQQHDAbljZfkuqwxDzANBgNVBAgMBuaxn+iLjzELMAkGA1UEBhMCQ04wHhcNMjAwNDE3MDYwNjA4WhcNMTkwOTAzMDE1MzE5WjCBrjFGMEQGA1UELQw9YXBpX2NhX1RFU1RfVE9fUEhfUkFfVE9OR0pJX2FlNTA3MGNiY2E4NTQyYzliYmJmOTRmZjcwNThkNmEzMTELMAkGA1UEBhMCQ04xDTALBgNVBAgMBG51bGwxDTALBgNVBAcMBG51bGwxFTATBgNVBAoMDENGQ0FTTTJBR0VOVDENMAsGA1UECwwEbnVsbDETMBEGA1UEAwwKY2hlbnh1QDEwNDBZMBMGByqGSM49AgEGCCqBHM9VAYItA0IABAWeikXULbz1RqgmVzJWtSDMa3f9wirzwnceb1WIWxTqJaY+3xNlsM63oaIKJCD6pZu14EDkLS0FTP1uX3EySOajbTBrMAsGA1UdDwQEAwIGwDAdBgNVHQ4EFgQUbMrrNQDS1B1yjyrkgq2FWGi5zRcwHwYDVR0jBBgwFoAUXPO6JYzCZQzsZ+++3Y1rp16v46wwDAYDVR0TBAUwAwEB/zAOBggqgRzQFAQBAQQCBQAwCgYIKoEcz1UBg3UDSQAwRgIhAMcbwSDvL78qDSoqQh/019EEk4UNHP7zko0t1GueffTnAiEAupHr3k4vWSWV1SEqds+q8u4CbRuuRDvBOQ6od8vGzjM=" 20 | decodeBytes, err := base64.StdEncoding.DecodeString(str) 21 | x, err := x509.ParseCertificate(decodeBytes) 22 | priv, err := sm2.GenerateKey(nil) // 生成密钥对 23 | if err != nil { 24 | fmt.Print(err) 25 | return 26 | } 27 | privPem, err := x509.WritePrivateKeyToPem(priv, nil) // 生成密钥文件 28 | if err != nil { 29 | t.Fatal(err) 30 | } 31 | err = ioutil.WriteFile("priv.pem", privPem, os.FileMode(0644)) 32 | if err != nil { 33 | t.Fatal(err) 34 | } 35 | privKey, err := x509.ReadPrivateKeyFromPem(privPem, nil) // 读取密钥 36 | if err != nil { 37 | t.Fatal(err) 38 | } 39 | SM2P12Encrypt(x, "123", privKey, "test.p12") //根据证书与私钥生成带密码的p12证书 40 | 41 | } 42 | func Test_P12Dncrypt(t *testing.T) { 43 | certificate, priv, err := SM2P12Decrypt("test.p12", "123") //根据密码读取P12证书 44 | if err != nil { 45 | t.Fatal(err) 46 | } 47 | privPem, _ := ioutil.ReadFile("priv.pem") 48 | privatekey, err := x509.ReadPrivateKeyFromPem(privPem, nil) 49 | if err != nil { 50 | t.Fatal(err) 51 | } 52 | fmt.Println(certificate.Issuer) 53 | fmt.Println(privatekey.D.Cmp(priv.D) == 0) 54 | fmt.Println(priv.IsOnCurve(priv.X, priv.Y)) 55 | } 56 | -------------------------------------------------------------------------------- /sm4/utils.go: -------------------------------------------------------------------------------- 1 | package sm4 2 | 3 | import ( 4 | "crypto/rand" 5 | "crypto/x509" 6 | "encoding/pem" 7 | "errors" 8 | "io/ioutil" 9 | ) 10 | 11 | // ReadKeyFromPem will return SM4Key from PEM format data. 12 | func ReadKeyFromPem(data []byte, pwd []byte) (SM4Key, error) { 13 | block, _ := pem.Decode(data) 14 | if block == nil { 15 | return nil, errors.New("SM4: pem decode failed") 16 | } 17 | if x509.IsEncryptedPEMBlock(block) { 18 | if block.Type != "SM4 ENCRYPTED KEY" { 19 | return nil, errors.New("SM4: unknown type") 20 | } 21 | if pwd == nil { 22 | return nil, errors.New("SM4: need passwd") 23 | } 24 | data, err := x509.DecryptPEMBlock(block, pwd) 25 | if err != nil { 26 | return nil, err 27 | } 28 | return data, nil 29 | } 30 | if block.Type != "SM4 KEY" { 31 | return nil, errors.New("SM4: unknown type") 32 | } 33 | return block.Bytes, nil 34 | } 35 | 36 | // ReadKeyFromPemFile will return SM4Key from filename that saved PEM format data. 37 | func ReadKeyFromPemFile(FileName string, pwd []byte) (SM4Key, error) { 38 | data, err := ioutil.ReadFile(FileName) 39 | if err != nil { 40 | return nil, err 41 | } 42 | return ReadKeyFromPem(data, pwd) 43 | } 44 | 45 | // WriteKeyToPem will convert SM4Key to PEM format data and return it. 46 | func WriteKeyToPem(key SM4Key, pwd []byte) ([]byte, error) { 47 | if pwd != nil { 48 | block, err := x509.EncryptPEMBlock(rand.Reader, 49 | "SM4 ENCRYPTED KEY", key, pwd, x509.PEMCipherAES256) //Use AES256 algorithms to encrypt SM4KEY 50 | if err != nil { 51 | return nil, err 52 | } 53 | return pem.EncodeToMemory(block), nil 54 | } else { 55 | block := &pem.Block{ 56 | Type: "SM4 KEY", 57 | Bytes: key, 58 | } 59 | return pem.EncodeToMemory(block), nil 60 | } 61 | } 62 | 63 | // WriteKeyToPemFile will convert SM4Key to PEM format data, then write it 64 | // into the input filename. 65 | func WriteKeyToPemFile(FileName string, key SM4Key, pwd []byte) error { 66 | var block *pem.Block 67 | var err error 68 | if pwd != nil { 69 | block, err = x509.EncryptPEMBlock(rand.Reader, 70 | "SM4 ENCRYPTED KEY", key, pwd, x509.PEMCipherAES256) 71 | if err != nil { 72 | return err 73 | } 74 | } else { 75 | block = &pem.Block{ 76 | Type: "SM4 KEY", 77 | Bytes: key, 78 | } 79 | } 80 | pemBytes := pem.EncodeToMemory(block) 81 | err = ioutil.WriteFile(FileName, pemBytes, 0666) 82 | if err != nil { 83 | return err 84 | } 85 | return nil 86 | } 87 | -------------------------------------------------------------------------------- /gmtls/http_client.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Suzhou Tongji Fintech Research Institute 2017 All Rights Reserved. 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | package gmtls 17 | 18 | import ( 19 | "context" 20 | "net" 21 | "net/http" 22 | "time" 23 | 24 | "github.com/tjfoc/gmsm/x509" 25 | ) 26 | 27 | // NewHTTPSClient 创建国密HTTPS客户端,只对服务端进行身份认证(验证服务端证书)。 28 | // pool: 根证书链 29 | func NewHTTPSClient(pool *x509.CertPool) *http.Client { 30 | return &http.Client{ 31 | Transport: NewSimpleRoundTripper(&Config{ 32 | GMSupport: &GMSupport{}, 33 | RootCAs: pool, 34 | }), 35 | } 36 | } 37 | 38 | // NewAuthHTTPSClient 创建双向身份认证国密HTTPS客户端 39 | // 40 | // pool: 根证书链 41 | // clientAuthCert: 客户端认证密钥对和证书 42 | func NewAuthHTTPSClient(pool *x509.CertPool, clientAuthCert *Certificate) *http.Client { 43 | return &http.Client{ 44 | Transport: NewSimpleRoundTripper(&Config{ 45 | GMSupport: &GMSupport{}, 46 | RootCAs: pool, 47 | Certificates: []Certificate{*clientAuthCert}, 48 | }), 49 | } 50 | } 51 | 52 | // NewCustomHTTPSClient 创建自定义国密HTTPS客户端 53 | // 通过自定义TLS参数定制TLS实现细节,如进行双向身份认证等。 54 | func NewCustomHTTPSClient(config *Config) *http.Client { 55 | if config == nil { 56 | return &http.Client{} 57 | } 58 | 59 | return &http.Client{ 60 | Transport: newDefaultGMHttpClientTransport(config), 61 | } 62 | } 63 | 64 | func newDefaultGMHttpClientTransport(tlsConfig *Config) http.RoundTripper { 65 | return &http.Transport{ 66 | DialTLSContext: func(ctx context.Context, network, addr string) (net.Conn, error) { 67 | 68 | dialer := &net.Dialer{} 69 | 70 | conn, err := DialWithDialer(dialer, network, addr, tlsConfig) 71 | if err != nil { 72 | return nil, err 73 | } 74 | 75 | return conn, nil 76 | }, 77 | Dial: (&net.Dialer{ 78 | Timeout: 10 * time.Second, 79 | KeepAlive: 60 * time.Second, 80 | }).Dial, 81 | TLSHandshakeTimeout: 10 * time.Second, 82 | IdleConnTimeout: 30 * time.Second, 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 更新日志 2 | ### 2.0 更新(June 9,2021) 3 | - [FIX] SM2公钥压缩格式前缀修改 4 | - [FIX]]国密tls部分bug修改 5 | - [FIX]]SM4_gcm模式bug修改 6 | - [New] 公私钥16进制格式导入导出 7 | - [New] SM4加密可设置IV值 8 | - [New] 国密tls与非国密自适应实现 9 | 10 | 11 | ### 1.4 更新(Sep 15,2020) 12 | **破坏性更新** 13 | - [FIX] SM2 生成私钥、签名及加密方法加入随机数,可使用外部随机数。 14 | - [FIX] 公私钥及证书从pem格式[]byte数据中导入导出,不再从pem格式File文件导入导出。 15 | - [FIX] SM2证书相关实现代码单独移至X509包中。 16 | - [FIX] 代码优化,删除无用方法 17 | - [New] SM4加密ecb、cbc模式实现 18 | - [New] 国密tls实现移至该库gmtls包中 19 | - [New] 国密tls实现使用双证书 20 | 21 | ### 1.2 更新(Feb 20, 2019) 22 | 23 | - [NEW] 实现PKCS#7签名及验签 24 | - [FIX] SM2 签名及验签方法完全遵循标准GM/T 0003系列,兼容CFCA Java-SDK 25 | 26 | **破坏性更新,证书与之前版本不兼容** 27 | 28 | ### 1.1.1更新 29 | - 新增以下函数支持用户其他信息
30 | SignDigitToSignData 将签名所得的大数r和s转换为签名的格式
31 | Sm2Sign 支持用户信息的签名
32 | Sm2Verify 支持用户信息的验签
33 | 34 | 35 | ### 1.1.0更新: 36 | - 改进新能,具体提升如下 37 |  注:本次优化并不彻底,只是第一次尝试优化,后续有时间还会继续优化 38 | ``` 39 | old: 40 | generate key: 41 | BenchmarkSM2-4 1000 2517147 ns/op 1156476 B/op 11273 allocs/op 42 | sign: 43 | BenchmarkSM2-4 300 6297498 ns/op 2321890 B/op 22653 allocs/op 44 | verify: 45 | BenchmarkSM2-4 2000 8557215 ns/op 3550626 B/op 34627 allocs/op 46 | encrypt: 47 | BenchmarkSM2-4 2000 8304840 ns/op 3483113 B/op 33967 allocs/op 48 | decrypt: 49 | BenchmarkSM2-4 2000 5726181 ns/op 2321728 B/op 22644 allocs/op 50 | new: 51 | generate key: 52 | BenchmarkSM2-4 5000 303656 ns/op 2791 B/op 41 allocs/op 53 | sign: 54 | BenchmarkSM2-4 2000 652465 ns/op 8828 B/op 133 allocs/op 55 | verify: 56 | BenchmarkSM2-4 1000 2004511 ns/op 122709 B/op 1738 allocs/op 57 | encrpyt: 58 | BenchmarkSM2-4 1000 1984419 ns/op 118560 B/op 1687 allocs/op 59 | decrypt: 60 | BenchmarkSM2-4 1000 1725001 ns/op 118331 B/op 1679 allocs/op 61 | ``` 62 | 63 | ### 1.0.1 更新: 64 | - 添加全局的sbox改进sm4效率(by https://github.com/QwertyJack) 65 | 66 | 67 | ### 1.0 更新: 68 | - 添加以下oid
69 | SM3WithSM2 1.2.156.10197.1.501
70 | SHA1WithSM2 1.2.156.10197.1.502
71 | SHA256WithSM2 1.2.156.10197.1.503
72 | 73 | - x509生成的证书如今可以使用SM3作为hash算法 74 | 75 | - 引入了以下hash算法 76 | RIPEMD160
77 | SHA3_256
78 | SHA3_384
79 | SHA3_512
80 | SHA3_SM3
81 | 用户需要自己安装golang.org/x/crypto 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /gmtls/gm_handshake_messages.go: -------------------------------------------------------------------------------- 1 | // Copyright 2009 The Go Authors. All rights reserved. 2 | // Copyright 2009 The Go Authors. All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package gmtls 7 | 8 | import "bytes" 9 | 10 | type certificateRequestMsgGM struct { 11 | raw []byte 12 | 13 | certificateTypes []byte 14 | certificateAuthorities [][]byte 15 | } 16 | 17 | func (m *certificateRequestMsgGM) equal(i interface{}) bool { 18 | m1, ok := i.(*certificateRequestMsgGM) 19 | if !ok { 20 | return false 21 | } 22 | 23 | return bytes.Equal(m.raw, m1.raw) && 24 | bytes.Equal(m.certificateTypes, m1.certificateTypes) && 25 | eqByteSlices(m.certificateAuthorities, m1.certificateAuthorities) 26 | } 27 | 28 | func (m *certificateRequestMsgGM) marshal() (x []byte) { 29 | if m.raw != nil { 30 | return m.raw 31 | } 32 | 33 | // See https://tools.ietf.org/html/rfc4346#section-7.4.4 34 | length := 1 + len(m.certificateTypes) + 2 35 | casLength := 0 36 | for _, ca := range m.certificateAuthorities { 37 | casLength += 2 + len(ca) 38 | } 39 | length += casLength 40 | 41 | x = make([]byte, 4+length) 42 | x[0] = typeCertificateRequest 43 | x[1] = uint8(length >> 16) 44 | x[2] = uint8(length >> 8) 45 | x[3] = uint8(length) 46 | 47 | x[4] = uint8(len(m.certificateTypes)) 48 | 49 | copy(x[5:], m.certificateTypes) 50 | y := x[5+len(m.certificateTypes):] 51 | 52 | y[0] = uint8(casLength >> 8) 53 | y[1] = uint8(casLength) 54 | y = y[2:] 55 | for _, ca := range m.certificateAuthorities { 56 | y[0] = uint8(len(ca) >> 8) 57 | y[1] = uint8(len(ca)) 58 | y = y[2:] 59 | copy(y, ca) 60 | y = y[len(ca):] 61 | } 62 | 63 | m.raw = x 64 | return 65 | } 66 | 67 | func (m *certificateRequestMsgGM) unmarshal(data []byte) bool { 68 | m.raw = data 69 | 70 | if len(data) < 5 { 71 | return false 72 | } 73 | 74 | length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3]) 75 | if uint32(len(data))-4 != length { 76 | return false 77 | } 78 | 79 | numCertTypes := int(data[4]) 80 | data = data[5:] 81 | if numCertTypes == 0 || len(data) <= numCertTypes { 82 | return false 83 | } 84 | 85 | m.certificateTypes = make([]byte, numCertTypes) 86 | if copy(m.certificateTypes, data) != numCertTypes { 87 | return false 88 | } 89 | 90 | data = data[numCertTypes:] 91 | 92 | if len(data) < 2 { 93 | return false 94 | } 95 | casLength := uint16(data[0])<<8 | uint16(data[1]) 96 | data = data[2:] 97 | if len(data) < int(casLength) { 98 | return false 99 | } 100 | cas := make([]byte, casLength) 101 | copy(cas, data) 102 | data = data[casLength:] 103 | 104 | m.certificateAuthorities = nil 105 | for len(cas) > 0 { 106 | if len(cas) < 2 { 107 | return false 108 | } 109 | caLen := uint16(cas[0])<<8 | uint16(cas[1]) 110 | cas = cas[2:] 111 | 112 | if len(cas) < int(caLen) { 113 | return false 114 | } 115 | 116 | m.certificateAuthorities = append(m.certificateAuthorities, cas[:caLen]) 117 | cas = cas[caLen:] 118 | } 119 | 120 | return len(data) == 0 121 | } 122 | 123 | -------------------------------------------------------------------------------- /gmtls/gmcredentials/credentials_test.go: -------------------------------------------------------------------------------- 1 | package gmcredentials 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "log" 7 | "net" 8 | "testing" 9 | "time" 10 | 11 | "github.com/tjfoc/gmsm/gmtls" 12 | "github.com/tjfoc/gmsm/gmtls/gmcredentials/echo" 13 | "github.com/tjfoc/gmsm/x509" 14 | "golang.org/x/net/context" 15 | "google.golang.org/grpc" 16 | ) 17 | 18 | const ( 19 | port = ":50051" 20 | address = "localhost:50051" 21 | ) 22 | 23 | var end chan bool 24 | 25 | type server struct{} 26 | 27 | func (s *server) Echo(ctx context.Context, req *echo.EchoRequest) (*echo.EchoResponse, error) { 28 | return &echo.EchoResponse{Result: req.Req}, nil 29 | } 30 | 31 | const ca = "testdata/ca.cert" 32 | const signCert = "testdata/sign.cert" 33 | const signKey = "testdata/sign.key" 34 | const encryptCert = "testdata/encrypt.cert" 35 | const encryptKey = "testdata/encrypt.key" 36 | 37 | const userCert = "testdata/user.cert" 38 | const userKey = "testdata/user.key" 39 | 40 | func serverRun() { 41 | signCert, err := gmtls.LoadX509KeyPair(signCert, signKey) 42 | if err != nil { 43 | log.Fatal(err) 44 | } 45 | 46 | encryptCert, err := gmtls.LoadX509KeyPair(encryptCert, encryptKey) 47 | if err != nil { 48 | log.Fatal(err) 49 | } 50 | certPool := x509.NewCertPool() 51 | cacert, err := ioutil.ReadFile(ca) 52 | if err != nil { 53 | log.Fatal(err) 54 | } 55 | certPool.AppendCertsFromPEM(cacert) 56 | lis, err := net.Listen("tcp", port) 57 | if err != nil { 58 | log.Fatalf("fail to listen: %v", err) 59 | } 60 | creds := NewTLS(&gmtls.Config{ 61 | GMSupport: &gmtls.GMSupport{}, 62 | ClientAuth: gmtls.RequireAndVerifyClientCert, 63 | Certificates: []gmtls.Certificate{signCert, encryptCert}, 64 | ClientCAs: certPool, 65 | }) 66 | s := grpc.NewServer(grpc.Creds(creds)) 67 | echo.RegisterEchoServer(s, &server{}) 68 | err = s.Serve(lis) 69 | if err != nil { 70 | log.Fatalf("Serve: %v", err) 71 | } 72 | } 73 | 74 | func clientRun() { 75 | cert, err := gmtls.LoadX509KeyPair(userCert, userKey) 76 | if err != nil { 77 | log.Fatal(err) 78 | } 79 | certPool := x509.NewCertPool() 80 | cacert, err := ioutil.ReadFile(ca) 81 | if err != nil { 82 | log.Fatal(err) 83 | } 84 | certPool.AppendCertsFromPEM(cacert) 85 | creds := NewTLS(&gmtls.Config{ 86 | GMSupport: &gmtls.GMSupport{}, 87 | ServerName: "test.example.com", 88 | Certificates: []gmtls.Certificate{cert}, 89 | RootCAs: certPool, 90 | ClientAuth: gmtls.RequireAndVerifyClientCert, 91 | }) 92 | conn, err := grpc.Dial(address, grpc.WithTransportCredentials(creds)) 93 | if err != nil { 94 | log.Fatalf("cannot to connect: %v", err) 95 | } 96 | defer conn.Close() 97 | c := echo.NewEchoClient(conn) 98 | echoTest(c) 99 | end <- true 100 | } 101 | 102 | func echoTest(c echo.EchoClient) { 103 | r, err := c.Echo(context.Background(), &echo.EchoRequest{Req: "hello"}) 104 | if err != nil { 105 | log.Fatalf("failed to echo: %v", err) 106 | } 107 | fmt.Printf("%s\n", r.Result) 108 | } 109 | 110 | func Test(t *testing.T) { 111 | end = make(chan bool, 64) 112 | go serverRun() 113 | time.Sleep(1000000) 114 | go clientRun() 115 | <-end 116 | } 117 | -------------------------------------------------------------------------------- /sm4/padding/pkcs7_padding_io.go: -------------------------------------------------------------------------------- 1 | package padding 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "io" 7 | ) 8 | 9 | // PKCS7PaddingReader 符合PKCS#7填充的输入流 10 | type PKCS7PaddingReader struct { 11 | fIn io.Reader 12 | padding io.Reader 13 | blockSize int 14 | readed int64 15 | eof bool 16 | eop bool 17 | } 18 | 19 | // NewPKCS7PaddingReader 创建PKCS7填充Reader 20 | // in: 输入流 21 | // blockSize: 分块大小 22 | func NewPKCS7PaddingReader(in io.Reader, blockSize int) *PKCS7PaddingReader { 23 | return &PKCS7PaddingReader{ 24 | fIn: in, 25 | padding: nil, 26 | eof: false, 27 | eop: false, 28 | blockSize: blockSize, 29 | } 30 | } 31 | 32 | func (p *PKCS7PaddingReader) Read(buf []byte) (int, error) { 33 | /* 34 | - 读取文件 35 | - 文件长度充足, 直接返还 36 | - 不充足 37 | - 读取到 n 字节, 剩余需要 m 字节 38 | - 从 padding 中读取然后追加到 buff 39 | - EOF 直接返回, 整个Reader end 40 | */ 41 | // 都读取完了 42 | if p.eof && p.eop { 43 | return 0, io.EOF 44 | } 45 | 46 | var n, off = 0, 0 47 | var err error 48 | if !p.eof { 49 | // 读取文件 50 | n, err = p.fIn.Read(buf) 51 | if err != nil && !errors.Is(err, io.EOF) { 52 | // 错误返回 53 | return 0, err 54 | } 55 | p.readed += int64(n) 56 | if errors.Is(err, io.EOF) { 57 | // 标志文件结束 58 | p.eof = true 59 | } 60 | if n == len(buf) { 61 | // 长度足够直接返回 62 | return n, nil 63 | } 64 | // 文件长度已经不足,根据已经已经读取的长度创建Padding 65 | p.newPadding() 66 | // 长度不足向Padding中索要 67 | off = n 68 | } 69 | 70 | if !p.eop { 71 | // 读取流 72 | var n2 = 0 73 | n2, err = p.padding.Read(buf[off:]) 74 | n += n2 75 | if errors.Is(err, io.EOF) { 76 | p.eop = true 77 | } 78 | } 79 | return n, err 80 | } 81 | 82 | // 新建Padding 83 | func (p *PKCS7PaddingReader) newPadding() { 84 | if p.padding != nil { 85 | return 86 | } 87 | size := p.blockSize - int(p.readed%int64(p.blockSize)) 88 | padding := bytes.Repeat([]byte{byte(size)}, size) 89 | p.padding = bytes.NewReader(padding) 90 | } 91 | 92 | // PKCS7PaddingWriter 符合PKCS#7去除的输入流,最后一个 分组根据会根据填充情况去除填充。 93 | type PKCS7PaddingWriter struct { 94 | cache *bytes.Buffer // 缓存区 95 | swap []byte // 临时交换区 96 | out io.Writer // 输出位置 97 | blockSize int // 分块大小 98 | } 99 | 100 | // NewPKCS7PaddingWriter PKCS#7 填充Writer 可以去除填充 101 | func NewPKCS7PaddingWriter(out io.Writer, blockSize int) *PKCS7PaddingWriter { 102 | cache := bytes.NewBuffer(make([]byte, 0, 1024)) 103 | swap := make([]byte, 1024) 104 | return &PKCS7PaddingWriter{out: out, blockSize: blockSize, cache: cache, swap: swap} 105 | } 106 | 107 | // Write 保留一个填充大小的数据,其余全部写入输出中 108 | func (p *PKCS7PaddingWriter) Write(buff []byte) (n int, err error) { 109 | // 写入缓存 110 | n, err = p.cache.Write(buff) 111 | if err != nil { 112 | return 0, err 113 | } 114 | if p.cache.Len() > p.blockSize { 115 | // 把超过一个分组长度的部分读取出来,写入到实际的out中 116 | size := p.cache.Len() - p.blockSize 117 | _, _ = p.cache.Read(p.swap[:size]) 118 | _, err = p.out.Write(p.swap[:size]) 119 | if err != nil { 120 | return 0, err 121 | } 122 | } 123 | return n, err 124 | 125 | } 126 | 127 | // Final 去除填充写入最后一个分块 128 | func (p *PKCS7PaddingWriter) Final() error { 129 | // 在Write 之后 cache 只会保留一个Block长度数据 130 | b := p.cache.Bytes() 131 | length := len(b) 132 | if length != p.blockSize { 133 | return errors.New("非法的PKCS7填充") 134 | } 135 | if length == 0 { 136 | return nil 137 | } 138 | unpadding := int(b[length-1]) 139 | if unpadding > p.blockSize || unpadding == 0 { 140 | return errors.New("非法的PKCS7填充") 141 | } 142 | _, err := p.out.Write(b[:(length - unpadding)]) 143 | return err 144 | } 145 | -------------------------------------------------------------------------------- /pkcs12/safebags.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package pkcs12 6 | 7 | import ( 8 | "crypto/rand" 9 | "encoding/asn1" 10 | "errors" 11 | ) 12 | 13 | var ( 14 | // see https://tools.ietf.org/html/rfc7292#appendix-D 15 | oidCertTypeX509Certificate = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 9, 22, 1}) 16 | oidPKCS8ShroundedKeyBag = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 10, 1, 2}) 17 | oidCertBag = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 10, 1, 3}) 18 | ) 19 | 20 | type certBag struct { 21 | Id asn1.ObjectIdentifier 22 | Data []byte `asn1:"tag:0,explicit"` 23 | } 24 | 25 | func decodePkcs8ShroudedKeyBag(asn1Data, password []byte) (privateKey interface{}, err error) { 26 | pkinfo := new(encryptedPrivateKeyInfo) 27 | if err = unmarshal(asn1Data, pkinfo); err != nil { 28 | return nil, errors.New("go-pkcs12: error decoding PKCS#8 shrouded key bag: " + err.Error()) 29 | } 30 | 31 | pkData, err := pbDecrypt(pkinfo, password) 32 | if err != nil { 33 | return nil, errors.New("go-pkcs12: error decrypting PKCS#8 shrouded key bag: " + err.Error()) 34 | } 35 | 36 | ret := new(asn1.RawValue) 37 | if err = unmarshal(pkData, ret); err != nil { 38 | return nil, errors.New("go-pkcs12: error unmarshaling decrypted private key: " + err.Error()) 39 | } 40 | 41 | if privateKey, err = ParsePKCS8PrivateKey(pkData); err != nil { 42 | return nil, errors.New("go-pkcs12: error parsing PKCS#8 private key: " + err.Error()) 43 | } 44 | 45 | return privateKey, nil 46 | } 47 | 48 | func encodePkcs8ShroudedKeyBag(privateKey interface{}, password []byte) (asn1Data []byte, err error) { 49 | var pkData []byte 50 | if pkData, err = marshalPKCS8PrivateKey(privateKey); err != nil { 51 | return nil, errors.New("go-pkcs12: error encoding PKCS#8 private key: " + err.Error()) 52 | } 53 | 54 | randomSalt := make([]byte, 8) 55 | if _, err = rand.Read(randomSalt); err != nil { 56 | return nil, errors.New("go-pkcs12: error reading random salt: " + err.Error()) 57 | } 58 | var paramBytes []byte 59 | if paramBytes, err = asn1.Marshal(pbeParams{Salt: randomSalt, Iterations: 2048}); err != nil { 60 | return nil, errors.New("go-pkcs12: error encoding params: " + err.Error()) 61 | } 62 | 63 | var pkinfo encryptedPrivateKeyInfo 64 | pkinfo.AlgorithmIdentifier.Algorithm = oidPBEWithSHAAnd3KeyTripleDESCBC 65 | pkinfo.AlgorithmIdentifier.Parameters.FullBytes = paramBytes 66 | 67 | if err = pbEncrypt(&pkinfo, pkData, password); err != nil { 68 | return nil, errors.New("go-pkcs12: error encrypting PKCS#8 shrouded key bag: " + err.Error()) 69 | } 70 | 71 | if asn1Data, err = asn1.Marshal(pkinfo); err != nil { 72 | return nil, errors.New("go-pkcs12: error encoding PKCS#8 shrouded key bag: " + err.Error()) 73 | } 74 | 75 | return asn1Data, nil 76 | } 77 | 78 | func decodeCertBag(asn1Data []byte) (x509Certificates []byte, err error) { 79 | bag := new(certBag) 80 | if err := unmarshal(asn1Data, bag); err != nil { 81 | return nil, errors.New("go-pkcs12: error decoding cert bag: " + err.Error()) 82 | } 83 | if !bag.Id.Equal(oidCertTypeX509Certificate) { 84 | return nil, NotImplementedError("only X509 certificates are supported") 85 | } 86 | return bag.Data, nil 87 | } 88 | 89 | func encodeCertBag(x509Certificates []byte) (asn1Data []byte, err error) { 90 | var bag certBag 91 | bag.Id = oidCertTypeX509Certificate 92 | bag.Data = x509Certificates 93 | if asn1Data, err = asn1.Marshal(bag); err != nil { 94 | return nil, errors.New("go-pkcs12: error encoding cert bag: " + err.Error()) 95 | } 96 | return asn1Data, nil 97 | } 98 | -------------------------------------------------------------------------------- /API使用说明.md: -------------------------------------------------------------------------------- 1 | # 国密GM/T Go API使用说明 2 | 3 | 4 | 5 | - [国密GM/T Go API使用说明](#国密gmt-go-api使用说明) 6 | - [Go包安装](#go包安装) 7 | - [SM2椭圆曲线公钥密码算法](#sm2椭圆曲线公钥密码算法) 8 | - [代码示例](#代码示例) 9 | - [SM3密码杂凑算法](#sm3密码杂凑算法) 10 | - [代码示例](#代码示例-1) 11 | - [SM4分组密码算法](#sm4分组密码算法) 12 | - [代码示例](#代码示例-2) 13 | - [相关代码示例参考](#相关代码示例参考) 14 | - [国密SSL(TLCP)](#国密ssltlcp) 15 | 16 | 17 | 18 | ## Go包安装 19 | 20 | ```bash 21 | go get -u github.com/tjfoc/gmsm 22 | ``` 23 | ## SM2椭圆曲线公钥密码算法 24 | 25 | > SM2椭圆曲线公钥密码算法 Public key cryptographic algorithm SM2 based on elliptic curves 26 | 27 | - 遵循的SM2标准号为: GM/T 0003.1-2012、GM/T 0003.2-2012、GM/T 0003.3-2012、GM/T 0003.4-2012、GM/T 0003.5-2012、GM/T 0009-2012、GM/T 0010-2012 28 | - go package: `github.com/tjfoc/gmsm/sm2` 29 | 30 | ### 代码示例 31 | 32 | ```Go 33 | priv, err := sm2.GenerateKey(rand.Reader) // 生成密钥对 34 | if err != nil { 35 | log.Fatal(err) 36 | } 37 | msg := []byte("Tongji Fintech Research Institute") 38 | pub := &priv.PublicKey 39 | ciphertxt, err := pub.EncryptAsn1(msg,rand.Reader) //sm2加密 40 | if err != nil { 41 | log.Fatal(err) 42 | } 43 | fmt.Printf("加密结果:%x\n",ciphertxt) 44 | plaintxt,err := priv.DecryptAsn1(ciphertxt) //sm2解密 45 | if err != nil { 46 | log.Fatal(err) 47 | } 48 | if !bytes.Equal(msg,plaintxt){ 49 | log.Fatal("原文不匹配") 50 | } 51 | 52 | sign,err := priv.Sign(rand.Reader, msg, nil) //sm2签名 53 | if err != nil { 54 | log.Fatal(err) 55 | } 56 | isok := pub.Verify(msg, sign) //sm2验签 57 | fmt.Printf("Verified: %v\n", isok) 58 | ``` 59 | ## SM3密码杂凑算法 60 | 61 | > SM3密码杂凑算法 - SM3 cryptographic hash algorithm 62 | 63 | - 遵循的SM3标准号为: GM/T 0004-2012 64 | - g package:`github.com/tjfoc/gmsm/sm3` 65 | - `type SM3 struct` 是原生接口hash.Hash的一个实现 66 | 67 | ### 代码示例 68 | 69 | ```Go 70 | data := "test" 71 | h := sm3.New() 72 | h.Write([]byte(data)) 73 | sum := h.Sum(nil) 74 | fmt.Printf("digest value is: %x\n",sum) 75 | ``` 76 | 77 | ## SM4分组密码算法 78 | 79 | > SM4分组密码算法 - SM4 block cipher algorithm 80 | 81 | - 遵循的SM4标准号为: GM/T 0002-2012 82 | - go package:`github.com/tjfoc/gmsm/sm4` 83 | 84 | ### 代码示例 85 | 86 | ```Go 87 | import "crypto/cipher" 88 | import "github.com/tjfoc/gmsm/sm4" 89 | import "fmt" 90 | 91 | func main(){ 92 | key := []byte("1234567890abcdef") 93 | fmt.Printf("key = %v\n", key) 94 | data := []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10} 95 | fmt.Printf("key = %v\n", key) 96 | fmt.Printf("data = %x\n", data) 97 | iv := []byte("0000000000000000") 98 | err = SetIV(iv)//设置SM4算法实现的IV值,不设置则使用默认值 99 | ecbMsg, err :=sm4.Sm4Ecb(key, data, true) //sm4Ecb模式pksc7填充加密 100 | if err != nil { 101 | t.Errorf("sm4 enc error:%s", err) 102 | return 103 | } 104 | fmt.Printf("ecbMsg = %x\n", ecbMsg) 105 | ecbDec, err := sm4.Sm4Ecb(key, ecbMsg, false) //sm4Ecb模式pksc7填充解密 106 | if err != nil { 107 | t.Errorf("sm4 dec error:%s", err) 108 | return 109 | } 110 | fmt.Printf("ecbDec = %x\n", ecbDec) 111 | } 112 | ``` 113 | 114 | 115 | ## 相关代码示例参考 116 | 117 | - [SM2算法 sm2/sm2_test.go](sm2/sm2_test.go) 118 | - [SM3算法 sm3/sm3_test.go](sm3/sm3_test.go) 119 | - [SM4算法 sm4/sm4_test.go](sm4/sm4_test.go) 120 | - [x509国密证书 x509/x509_test.go](x509/x509_test.go) 121 | 122 | ## 国密SSL(TLCP) 123 | 124 | - 国密SSL协议遵循标准:《GM/T 0024-2014 SSL VPN技术规范》 125 | - **国密SSL协议目前升级为TLCP协议,遵循《GBT 38636-2020 信息安全技术 传输层密码协议》**,新增了SM4的GCM加密模式。 126 | 127 | 国密SSL使用详情见文档: [《tjfoc 国密SSL协议快速入门》](gmtls/websvr/README.md) 128 | 129 | 示例入口: 130 | 131 | - [国密HTTPS Web服务器测试用例 gmtls/websvr/websvr.go](gmtls/websvr/websvr.go) 132 | - [国密TLS GRPC测试用例 gmtls/websvr/credentials_test.go](gmtls/gmcredentials/credentials_test.go) 133 | -------------------------------------------------------------------------------- /x509/pkcs1.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Suzhou Tongji Fintech Research Institute 2017 All Rights Reserved. 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | package x509 17 | 18 | import ( 19 | "crypto/rsa" 20 | "encoding/asn1" 21 | "errors" 22 | "math/big" 23 | ) 24 | 25 | // pkcs1PrivateKey is a structure which mirrors the PKCS#1 ASN.1 for an RSA private key. 26 | type pkcs1PrivateKey struct { 27 | Version int 28 | N *big.Int 29 | E int 30 | D *big.Int 31 | P *big.Int 32 | Q *big.Int 33 | // We ignore these values, if present, because rsa will calculate them. 34 | Dp *big.Int `asn1:"optional"` 35 | Dq *big.Int `asn1:"optional"` 36 | Qinv *big.Int `asn1:"optional"` 37 | 38 | AdditionalPrimes []pkcs1AdditionalRSAPrime `asn1:"optional,omitempty"` 39 | } 40 | 41 | type pkcs1AdditionalRSAPrime struct { 42 | Prime *big.Int 43 | 44 | // We ignore these values because rsa will calculate them. 45 | Exp *big.Int 46 | Coeff *big.Int 47 | } 48 | 49 | // ParsePKCS1PrivateKey returns an RSA private key from its ASN.1 PKCS#1 DER encoded form. 50 | func ParsePKCS1PrivateKey(der []byte) (*rsa.PrivateKey, error) { 51 | var priv pkcs1PrivateKey 52 | rest, err := asn1.Unmarshal(der, &priv) 53 | if len(rest) > 0 { 54 | return nil, asn1.SyntaxError{Msg: "trailing data"} 55 | } 56 | if err != nil { 57 | return nil, err 58 | } 59 | 60 | if priv.Version > 1 { 61 | return nil, errors.New("x509: unsupported private key version") 62 | } 63 | 64 | if priv.N.Sign() <= 0 || priv.D.Sign() <= 0 || priv.P.Sign() <= 0 || priv.Q.Sign() <= 0 { 65 | return nil, errors.New("x509: private key contains zero or negative value") 66 | } 67 | 68 | key := new(rsa.PrivateKey) 69 | key.PublicKey = rsa.PublicKey{ 70 | E: priv.E, 71 | N: priv.N, 72 | } 73 | 74 | key.D = priv.D 75 | key.Primes = make([]*big.Int, 2+len(priv.AdditionalPrimes)) 76 | key.Primes[0] = priv.P 77 | key.Primes[1] = priv.Q 78 | for i, a := range priv.AdditionalPrimes { 79 | if a.Prime.Sign() <= 0 { 80 | return nil, errors.New("x509: private key contains zero or negative prime") 81 | } 82 | key.Primes[i+2] = a.Prime 83 | // We ignore the other two values because rsa will calculate 84 | // them as needed. 85 | } 86 | 87 | err = key.Validate() 88 | if err != nil { 89 | return nil, err 90 | } 91 | key.Precompute() 92 | 93 | return key, nil 94 | } 95 | 96 | // MarshalPKCS1PrivateKey converts a private key to ASN.1 DER encoded form. 97 | func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte { 98 | key.Precompute() 99 | 100 | version := 0 101 | if len(key.Primes) > 2 { 102 | version = 1 103 | } 104 | 105 | priv := pkcs1PrivateKey{ 106 | Version: version, 107 | N: key.N, 108 | E: key.PublicKey.E, 109 | D: key.D, 110 | P: key.Primes[0], 111 | Q: key.Primes[1], 112 | Dp: key.Precomputed.Dp, 113 | Dq: key.Precomputed.Dq, 114 | Qinv: key.Precomputed.Qinv, 115 | } 116 | 117 | priv.AdditionalPrimes = make([]pkcs1AdditionalRSAPrime, len(key.Precomputed.CRTValues)) 118 | for i, values := range key.Precomputed.CRTValues { 119 | priv.AdditionalPrimes[i].Prime = key.Primes[2+i] 120 | priv.AdditionalPrimes[i].Exp = values.Exp 121 | priv.AdditionalPrimes[i].Coeff = values.Coeff 122 | } 123 | 124 | b, _ := asn1.Marshal(priv) 125 | return b 126 | } 127 | 128 | // rsaPublicKey reflects the ASN.1 structure of a PKCS#1 public key. 129 | type rsaPublicKey struct { 130 | N *big.Int 131 | E int 132 | } 133 | -------------------------------------------------------------------------------- /gmtls/alert.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Suzhou Tongji Fintech Research Institute 2017 All Rights Reserved. 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | package gmtls 17 | 18 | import "strconv" 19 | 20 | type alert uint8 21 | 22 | const ( 23 | // alert level 24 | alertLevelWarning = 1 25 | alertLevelError = 2 26 | ) 27 | 28 | const ( 29 | alertCloseNotify alert = 0 30 | alertUnexpectedMessage alert = 10 31 | alertBadRecordMAC alert = 20 32 | alertDecryptionFailed alert = 21 33 | alertRecordOverflow alert = 22 34 | alertDecompressionFailure alert = 30 35 | alertHandshakeFailure alert = 40 36 | alertBadCertificate alert = 42 37 | alertUnsupportedCertificate alert = 43 38 | alertCertificateRevoked alert = 44 39 | alertCertificateExpired alert = 45 40 | alertCertificateUnknown alert = 46 41 | alertIllegalParameter alert = 47 42 | alertUnknownCA alert = 48 43 | alertAccessDenied alert = 49 44 | alertDecodeError alert = 50 45 | alertDecryptError alert = 51 46 | alertProtocolVersion alert = 70 47 | alertInsufficientSecurity alert = 71 48 | alertInternalError alert = 80 49 | alertInappropriateFallback alert = 86 50 | alertUserCanceled alert = 90 51 | alertNoRenegotiation alert = 100 52 | alertNoApplicationProtocol alert = 120 53 | //GMT0024 54 | alertUnspporttedSite2Site alert = 200 55 | alertNoArea alert = 201 56 | alertUnspportedAreaType alert = 202 57 | alertBadIBCParam alert = 203 58 | alertUnspportedIBCParam alert = 204 59 | alertIdentityNeed alert = 205 60 | ) 61 | 62 | var alertText = map[alert]string{ 63 | alertCloseNotify: "close notify", 64 | alertUnexpectedMessage: "unexpected message", 65 | alertBadRecordMAC: "bad record MAC", 66 | alertDecryptionFailed: "decryption failed", 67 | alertRecordOverflow: "record overflow", 68 | alertDecompressionFailure: "decompression failure", 69 | alertHandshakeFailure: "handshake failure", 70 | alertBadCertificate: "bad certificate", 71 | alertUnsupportedCertificate: "unsupported certificate", 72 | alertCertificateRevoked: "revoked certificate", 73 | alertCertificateExpired: "expired certificate", 74 | alertCertificateUnknown: "unknown certificate", 75 | alertIllegalParameter: "illegal parameter", 76 | alertUnknownCA: "unknown certificate authority", 77 | alertAccessDenied: "access denied", 78 | alertDecodeError: "error decoding message", 79 | alertDecryptError: "error decrypting message", 80 | alertProtocolVersion: "protocol version not supported", 81 | alertInsufficientSecurity: "insufficient security level", 82 | alertInternalError: "internal error", 83 | alertInappropriateFallback: "inappropriate fallback", 84 | alertUserCanceled: "user canceled", 85 | alertNoRenegotiation: "no renegotiation", 86 | alertNoApplicationProtocol: "no application protocol", 87 | //GMT0024 88 | alertUnspporttedSite2Site: "不支持site2site", 89 | alertNoArea : "没有保护域", 90 | alertUnspportedAreaType : "不支持的保护域类型", 91 | alertBadIBCParam : "接收到一个无效的ibc公共参数", 92 | alertUnspportedIBCParam : "不支持ibc参数中定义的信息", 93 | alertIdentityNeed : "缺少对方的ibc标识", 94 | } 95 | 96 | func (e alert) String() string { 97 | s, ok := alertText[e] 98 | if ok { 99 | return "tls: " + s 100 | } 101 | return "tls: alert(" + strconv.Itoa(int(e)) + ")" 102 | } 103 | 104 | func (e alert) Error() string { 105 | return e.String() 106 | } 107 | -------------------------------------------------------------------------------- /sm4/sm4_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Suzhou Tongji Fintech Research Institute 2017 All Rights Reserved. 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | package sm4 17 | 18 | import ( 19 | "fmt" 20 | "reflect" 21 | "testing" 22 | ) 23 | 24 | func TestSM4(t *testing.T) { 25 | key := []byte("1234567890abcdef") 26 | 27 | fmt.Printf("key = %v\n", key) 28 | data := []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10} 29 | err := WriteKeyToPemFile("key.pem", key, nil) 30 | if err != nil { 31 | t.Fatalf("WriteKeyToPem error") 32 | } 33 | key, err = ReadKeyFromPemFile("key.pem", nil) 34 | fmt.Printf("key = %v\n", key) 35 | if err != nil { 36 | t.Fatal(err) 37 | } 38 | fmt.Printf("data = %x\n", data) 39 | ecbMsg, err := Sm4Ecb(key, data, true) 40 | if err != nil { 41 | t.Errorf("sm4 enc error:%s", err) 42 | return 43 | } 44 | fmt.Printf("ecbMsg = %x\n", ecbMsg) 45 | iv := []byte("0000000000000000") 46 | err = SetIV(iv) 47 | fmt.Printf("err = %v\n", err) 48 | ecbDec, err := Sm4Ecb(key, ecbMsg, false) 49 | if err != nil { 50 | t.Errorf("sm4 dec error:%s", err) 51 | return 52 | } 53 | fmt.Printf("ecbDec = %x\n", ecbDec) 54 | if !testCompare(data, ecbDec) { 55 | t.Errorf("sm4 self enc and dec failed") 56 | } 57 | cbcMsg, err := Sm4Cbc(key, data, true) 58 | if err != nil { 59 | t.Errorf("sm4 enc error:%s", err) 60 | } 61 | fmt.Printf("cbcMsg = %x\n", cbcMsg) 62 | cbcDec, err := Sm4Cbc(key, cbcMsg, false) 63 | if err != nil { 64 | t.Errorf("sm4 dec error:%s", err) 65 | return 66 | } 67 | fmt.Printf("cbcDec = %x\n", cbcDec) 68 | if !testCompare(data, cbcDec) { 69 | t.Errorf("sm4 self enc and dec failed") 70 | } 71 | 72 | cbcMsg, err = Sm4CFB(key, data, true) 73 | if err != nil { 74 | t.Errorf("sm4 enc error:%s", err) 75 | } 76 | fmt.Printf("cbcCFB = %x\n", cbcMsg) 77 | 78 | cbcCfb, err := Sm4CFB(key, cbcMsg, false) 79 | if err != nil { 80 | t.Errorf("sm4 dec error:%s", err) 81 | return 82 | } 83 | fmt.Printf("cbcCFB = %x\n", cbcCfb) 84 | 85 | cbcMsg, err = Sm4OFB(key, data, true) 86 | if err != nil { 87 | t.Errorf("sm4 enc error:%s", err) 88 | } 89 | fmt.Printf("cbcOFB = %x\n", cbcMsg) 90 | 91 | cbcOfc, err := Sm4OFB(key, cbcMsg, false) 92 | if err != nil { 93 | t.Errorf("sm4 dec error:%s", err) 94 | return 95 | } 96 | fmt.Printf("cbcOFB = %x\n", cbcOfc) 97 | } 98 | 99 | func BenchmarkSM4(t *testing.B) { 100 | t.ReportAllocs() 101 | key := []byte("1234567890abcdef") 102 | data := []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10} 103 | err := WriteKeyToPemFile("key.pem", key, nil) 104 | if err != nil { 105 | t.Fatalf("WriteKeyToPem error") 106 | } 107 | key, err = ReadKeyFromPemFile("key.pem", nil) 108 | if err != nil { 109 | t.Fatal(err) 110 | } 111 | c, err := NewCipher(key) 112 | if err != nil { 113 | t.Fatal(err) 114 | } 115 | 116 | for i := 0; i < t.N; i++ { 117 | d0 := make([]byte, 16) 118 | c.Encrypt(d0, data) 119 | d1 := make([]byte, 16) 120 | c.Decrypt(d1, d0) 121 | } 122 | } 123 | 124 | func TestErrKeyLen(t *testing.T) { 125 | fmt.Printf("\n--------------test key len------------------") 126 | key := []byte("1234567890abcdefg") 127 | _, err := NewCipher(key) 128 | if err != nil { 129 | fmt.Println("\nError key len !") 130 | } 131 | key = []byte("1234") 132 | _, err = NewCipher(key) 133 | if err != nil { 134 | fmt.Println("Error key len !") 135 | } 136 | fmt.Println("------------------end----------------------") 137 | } 138 | 139 | func testCompare(key1, key2 []byte) bool { 140 | if len(key1) != len(key2) { 141 | return false 142 | } 143 | for i, v := range key1 { 144 | if i == 1 { 145 | fmt.Println("type of v", reflect.TypeOf(v)) 146 | } 147 | a := key2[i] 148 | if a != v { 149 | return false 150 | } 151 | } 152 | return true 153 | } 154 | -------------------------------------------------------------------------------- /gmtls/websvr/websvr_test.go: -------------------------------------------------------------------------------- 1 | package websvr 2 | 3 | import ( 4 | "crypto/tls" 5 | "fmt" 6 | "github.com/tjfoc/gmsm/x509" 7 | "io/ioutil" 8 | "log" 9 | "net/http" 10 | "testing" 11 | "time" 12 | 13 | "github.com/tjfoc/gmsm/gmtls" 14 | ) 15 | 16 | const ( 17 | // rsaCertPath = "certs/rsa_sign.cer" 18 | // rsaKeyPath = "certs/rsa_sign_key.pem" 19 | rsaCacertPath = "certs/rsa_CA.cer" 20 | // sm2SignCertPath = "certs/sm2_sign_cert.cer" 21 | // sm2SignKeyPath = "certs/sm2_sign_key.pem" 22 | // sm2EncCertPath = "certs/sm2_enc_cert.cer" 23 | // sm2EncKeyPath = "certs/sm2_enc_key.pem" 24 | // SM2CaCertPath = "certs/SM2_CA.cer" 25 | sm2UserCertPath = "certs/sm2_auth_cert.cer" 26 | sm2UserKeyPath = "certs/sm2_auth_key.pem" 27 | ) 28 | 29 | func ServerRun() { 30 | //config, err := loadRsaConfig() 31 | //config, err := loadSM2Config() 32 | config, err := loadAutoSwitchConfig() 33 | //config, err:=loadAutoSwitchConfigClientAuth() 34 | if err != nil { 35 | panic(err) 36 | } 37 | 38 | ln, err := gmtls.Listen("tcp", ":50052", config) 39 | if err != nil { 40 | log.Println(err) 41 | return 42 | } 43 | defer ln.Close() 44 | 45 | http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) { 46 | fmt.Fprintf(writer, "hello\n") 47 | }) 48 | fmt.Println(">> HTTP Over [GMSSL/TLS] running...") 49 | err = http.Serve(ln, nil) 50 | if err != nil { 51 | panic(err) 52 | } 53 | } 54 | 55 | func ClientRun() { 56 | var config = tls.Config{ 57 | MaxVersion: gmtls.VersionTLS12, 58 | InsecureSkipVerify: true, 59 | } 60 | conn, err := tls.Dial("tcp", "localhost:50052", &config) 61 | if err != nil { 62 | panic(err) 63 | } 64 | defer conn.Close() 65 | 66 | req := []byte("GET / HTTP/1.1\r\n" + 67 | "Host: localhost\r\n" + 68 | "Connection: close\r\n\r\n") 69 | conn.Write(req) 70 | 71 | buff := make([]byte, 1024) 72 | for { 73 | n, _ := conn.Read(buff) 74 | if n <= 0 { 75 | break 76 | } else { 77 | fmt.Printf("%s", buff[0:n]) 78 | } 79 | } 80 | fmt.Println(">> RSA TLS [PASS]") 81 | end <- true 82 | } 83 | 84 | func gmClientRun() { 85 | 86 | // 信任的根证书 87 | certPool := x509.NewCertPool() 88 | cacert, err := ioutil.ReadFile(SM2CaCertPath) 89 | if err != nil { 90 | log.Fatal(err) 91 | } 92 | certPool.AppendCertsFromPEM(cacert) 93 | cert, err := gmtls.LoadX509KeyPair(sm2UserCertPath, sm2UserKeyPath) 94 | 95 | config := &gmtls.Config{ 96 | GMSupport: &gmtls.GMSupport{}, 97 | RootCAs: certPool, 98 | Certificates: []gmtls.Certificate{cert}, 99 | } 100 | 101 | conn, err := gmtls.Dial("tcp", "localhost:50052", config) 102 | if err != nil { 103 | panic(err) 104 | } 105 | defer conn.Close() 106 | 107 | req := []byte("GET / HTTP/1.1\r\n" + 108 | "Host: localhost\r\n" + 109 | "Connection: close\r\n\r\n") 110 | _, _ = conn.Write(req) 111 | buff := make([]byte, 1024) 112 | for { 113 | n, _ := conn.Read(buff) 114 | if n <= 0 { 115 | break 116 | } else { 117 | fmt.Printf("%s", buff[0:n]) 118 | } 119 | } 120 | fmt.Println(">> SM2_SM4_CBC_SM3 suite [PASS]") 121 | end <- true 122 | } 123 | 124 | // gmGCMClientRun GCM模式测试 125 | func gmGCMClientRun() { 126 | 127 | // 信任的根证书 128 | certPool := x509.NewCertPool() 129 | cacert, err := ioutil.ReadFile(SM2CaCertPath) 130 | if err != nil { 131 | log.Fatal(err) 132 | } 133 | certPool.AppendCertsFromPEM(cacert) 134 | cert, err := gmtls.LoadX509KeyPair(sm2UserCertPath, sm2UserKeyPath) 135 | 136 | config := &gmtls.Config{ 137 | GMSupport: &gmtls.GMSupport{}, 138 | RootCAs: certPool, 139 | Certificates: []gmtls.Certificate{cert}, 140 | CipherSuites: []uint16{gmtls.GMTLS_ECC_SM4_GCM_SM3}, 141 | } 142 | 143 | conn, err := gmtls.Dial("tcp", "localhost:50052", config) 144 | if err != nil { 145 | panic(err) 146 | } 147 | defer conn.Close() 148 | 149 | req := []byte("GET / HTTP/1.1\r\n" + 150 | "Host: localhost\r\n" + 151 | "Connection: close\r\n\r\n") 152 | _, _ = conn.Write(req) 153 | buff := make([]byte, 1024) 154 | for { 155 | n, _ := conn.Read(buff) 156 | if n <= 0 { 157 | break 158 | } else { 159 | fmt.Printf("%s", buff[0:n]) 160 | } 161 | } 162 | fmt.Println(">> SM2_SM4_GCM_SM3 suite [PASS]") 163 | end <- true 164 | } 165 | 166 | var end chan bool 167 | 168 | func Test_tls(t *testing.T) { 169 | end = make(chan bool, 64) 170 | go ServerRun() 171 | time.Sleep(time.Second) 172 | go ClientRun() 173 | <-end 174 | go gmClientRun() 175 | <-end 176 | go gmGCMClientRun() 177 | <-end 178 | 179 | } 180 | -------------------------------------------------------------------------------- /x509/pkcs7_test.go: -------------------------------------------------------------------------------- 1 | package x509 2 | 3 | import ( 4 | "crypto/x509/pkix" 5 | "encoding/asn1" 6 | "math/big" 7 | "net" 8 | "testing" 9 | "time" 10 | 11 | "github.com/tjfoc/gmsm/sm2" 12 | ) 13 | 14 | func TestPKCS7SM2(t *testing.T) { 15 | priv, err := sm2.GenerateKey(nil) // 生成密钥对 16 | if err != nil { 17 | t.Fatal(err) 18 | } 19 | privPem, err := WritePrivateKeyToPem(priv, nil) // 生成密钥文件 20 | if err != nil { 21 | t.Fatal(err) 22 | } 23 | pubKey, _ := priv.Public().(*sm2.PublicKey) 24 | pubkeyPem, err := WritePublicKeyToPem(pubKey) // 生成公钥文件 25 | privKey, err := ReadPrivateKeyFromPem(privPem, nil) // 读取密钥 26 | if err != nil { 27 | t.Fatal(err) 28 | } 29 | pubKey, err = ReadPublicKeyFromPem(pubkeyPem) // 读取公钥 30 | if err != nil { 31 | t.Fatal(err) 32 | } 33 | templateReq := CertificateRequest{ 34 | Subject: pkix.Name{ 35 | CommonName: "test.example.com", 36 | Organization: []string{"Test"}, 37 | }, 38 | // SignatureAlgorithm: ECDSAWithSHA256, 39 | SignatureAlgorithm: SM2WithSM3, 40 | } 41 | reqPem, err := CreateCertificateRequestToPem(&templateReq, privKey) 42 | if err != nil { 43 | t.Fatal(err) 44 | } 45 | req, err := ReadCertificateRequestFromPem(reqPem) 46 | if err != nil { 47 | t.Fatal(err) 48 | } 49 | err = req.CheckSignature() 50 | if err != nil { 51 | t.Fatalf("Request CheckSignature error:%v", err) 52 | } else { 53 | t.Log("CheckSignature ok") 54 | } 55 | testExtKeyUsage := []ExtKeyUsage{ExtKeyUsageClientAuth, ExtKeyUsageServerAuth} 56 | testUnknownExtKeyUsage := []asn1.ObjectIdentifier{[]int{1, 2, 3}, []int{2, 59, 1}} 57 | extraExtensionData := []byte("extra extension") 58 | commonName := "test.example.com" 59 | template := Certificate{ 60 | // SerialNumber is negative to ensure that negative 61 | // values are parsed. This is due to the prevalence of 62 | // buggy code that produces certificates with negative 63 | // serial numbers. 64 | SerialNumber: big.NewInt(-1), 65 | Subject: pkix.Name{ 66 | CommonName: commonName, 67 | Organization: []string{"TEST"}, 68 | Country: []string{"China"}, 69 | ExtraNames: []pkix.AttributeTypeAndValue{ 70 | { 71 | Type: []int{2, 5, 4, 42}, 72 | Value: "Gopher", 73 | }, 74 | // This should override the Country, above. 75 | { 76 | Type: []int{2, 5, 4, 6}, 77 | Value: "NL", 78 | }, 79 | }, 80 | }, 81 | NotBefore: time.Now(), 82 | NotAfter: time.Date(2021, time.October, 10, 12, 1, 1, 1, time.UTC), 83 | 84 | // SignatureAlgorithm: ECDSAWithSHA256, 85 | SignatureAlgorithm: SM2WithSM3, 86 | 87 | SubjectKeyId: []byte{1, 2, 3, 4}, 88 | KeyUsage: KeyUsageCertSign, 89 | 90 | ExtKeyUsage: testExtKeyUsage, 91 | UnknownExtKeyUsage: testUnknownExtKeyUsage, 92 | 93 | BasicConstraintsValid: true, 94 | IsCA: true, 95 | 96 | OCSPServer: []string{"http://ocsp.example.com"}, 97 | IssuingCertificateURL: []string{"http://crt.example.com/ca1.crt"}, 98 | 99 | DNSNames: []string{"test.example.com"}, 100 | EmailAddresses: []string{"gopher@golang.org"}, 101 | IPAddresses: []net.IP{net.IPv4(127, 0, 0, 1).To4(), net.ParseIP("2001:4860:0:2001::68")}, 102 | 103 | PolicyIdentifiers: []asn1.ObjectIdentifier{[]int{1, 2, 3}}, 104 | PermittedDNSDomains: []string{".example.com", "example.com"}, 105 | 106 | CRLDistributionPoints: []string{"http://crl1.example.com/ca1.crl", "http://crl2.example.com/ca1.crl"}, 107 | 108 | ExtraExtensions: []pkix.Extension{ 109 | { 110 | Id: []int{1, 2, 3, 4}, 111 | Value: extraExtensionData, 112 | }, 113 | // This extension should override the SubjectKeyId, above. 114 | { 115 | Id: oidExtensionSubjectKeyId, 116 | Critical: false, 117 | Value: []byte{0x04, 0x04, 4, 3, 2, 1}, 118 | }, 119 | }, 120 | } 121 | pubKey, _ = priv.Public().(*sm2.PublicKey) 122 | certpem, err := CreateCertificateToPem(&template, &template, pubKey, privKey) 123 | if err != nil { 124 | t.Fatal("failed to create cert file") 125 | } 126 | cert, err := ReadCertificateFromPem(certpem) 127 | if err != nil { 128 | t.Fatal("failed to read cert file") 129 | } 130 | err = cert.CheckSignature(cert.SignatureAlgorithm, cert.RawTBSCertificate, cert.Signature) 131 | if err != nil { 132 | t.Fatal(err) 133 | } else { 134 | t.Log("CheckSignature ok") 135 | } 136 | 137 | content := []byte("this is test") 138 | data, err := PKCS7EncryptSM2(content, []*Certificate{cert}, sm2.C1C3C2) 139 | if err != nil { 140 | t.Fatal("failed to PKCS7Encrypt ") 141 | } 142 | pk7Data, err := ParsePKCS7(data) 143 | 144 | if err != nil { 145 | t.Fatal("failed to ParsePKCS7 ") 146 | } 147 | decryptData, err := pk7Data.DecryptSM2(cert, priv, sm2.C1C3C2) 148 | if err != nil { 149 | t.Fatal("failed to PKCS7Decrypt ") 150 | } 151 | t.Log("decrypt success! data: ", string(decryptData)) 152 | } 153 | -------------------------------------------------------------------------------- /gmtls/websvr/websvr.go: -------------------------------------------------------------------------------- 1 | package websvr 2 | 3 | import ( 4 | "crypto/tls" 5 | x "crypto/x509" 6 | "github.com/tjfoc/gmsm/gmtls" 7 | "github.com/tjfoc/gmsm/x509" 8 | "io/ioutil" 9 | ) 10 | 11 | const ( 12 | rsaCertPath = "./certs/rsa_sign.cer" 13 | rsaKeyPath = "./certs/rsa_sign_key.pem" 14 | RSACaCertPath = "./certs/RSA_CA.cer" 15 | RSAAuthCertPath = "./certs/rsa_auth_cert.cer" 16 | RSAAuthKeyPath = "./certs/rsa_auth_key.pem" 17 | SM2CaCertPath = "./certs/SM2_CA.cer" 18 | SM2AuthCertPath = "./certs/sm2_auth_cert.cer" 19 | SM2AuthKeyPath = "./certs/sm2_auth_key.pem" 20 | sm2SignCertPath = "./certs/sm2_sign_cert.cer" 21 | sm2SignKeyPath = "./certs/sm2_sign_key.pem" 22 | sm2EncCertPath = "./certs/sm2_enc_cert.cer" 23 | sm2EncKeyPath = "./certs/sm2_enc_key.pem" 24 | ) 25 | 26 | // RSA配置 27 | func loadRsaConfig() (*gmtls.Config, error) { 28 | cert, err := gmtls.LoadX509KeyPair(rsaCertPath, rsaKeyPath) 29 | if err != nil { 30 | return nil, err 31 | } 32 | return &gmtls.Config{Certificates: []gmtls.Certificate{cert}}, nil 33 | } 34 | 35 | // SM2配置 36 | func loadSM2Config() (*gmtls.Config, error) { 37 | sigCert, err := gmtls.LoadX509KeyPair(sm2SignCertPath, sm2SignKeyPath) 38 | if err != nil { 39 | return nil, err 40 | } 41 | encCert, err := gmtls.LoadX509KeyPair(sm2EncCertPath, sm2EncKeyPath) 42 | if err != nil { 43 | return nil, err 44 | } 45 | return &gmtls.Config{ 46 | GMSupport: &gmtls.GMSupport{}, 47 | Certificates: []gmtls.Certificate{sigCert, encCert}, 48 | }, nil 49 | } 50 | 51 | // 切换GMSSL/TSL 52 | func loadAutoSwitchConfig() (*gmtls.Config, error) { 53 | rsaKeypair, err := gmtls.LoadX509KeyPair(rsaCertPath, rsaKeyPath) 54 | if err != nil { 55 | return nil, err 56 | } 57 | sigCert, err := gmtls.LoadX509KeyPair(sm2SignCertPath, sm2SignKeyPath) 58 | if err != nil { 59 | return nil, err 60 | } 61 | encCert, err := gmtls.LoadX509KeyPair(sm2EncCertPath, sm2EncKeyPath) 62 | if err != nil { 63 | return nil, err 64 | 65 | } 66 | return gmtls.NewBasicAutoSwitchConfig(&sigCert, &encCert, &rsaKeypair) 67 | } 68 | 69 | // 双向身份认证 服务端配置 70 | func loadServerMutualTLCPAuthConfig() (*gmtls.Config, error) { 71 | // 签名密钥对/证书 和 加密密钥对/证书 72 | sigCert, err := gmtls.LoadX509KeyPair(sm2SignCertPath, sm2SignKeyPath) 73 | if err != nil { 74 | return nil, err 75 | } 76 | encCert, err := gmtls.LoadX509KeyPair(sm2EncCertPath, sm2EncKeyPath) 77 | if err != nil { 78 | return nil, err 79 | 80 | } 81 | 82 | // 信任的根证书 83 | certPool := x509.NewCertPool() 84 | cacert, err := ioutil.ReadFile(SM2CaCertPath) 85 | if err != nil { 86 | return nil, err 87 | } 88 | certPool.AppendCertsFromPEM(cacert) 89 | 90 | return &gmtls.Config{ 91 | GMSupport: gmtls.NewGMSupport(), 92 | Certificates: []gmtls.Certificate{sigCert, encCert}, 93 | ClientCAs: certPool, 94 | ClientAuth: gmtls.RequireAndVerifyClientCert, 95 | }, nil 96 | } 97 | 98 | // 要求客户端身份认证 99 | func loadAutoSwitchConfigClientAuth() (*gmtls.Config, error) { 100 | config, err := loadAutoSwitchConfig() 101 | if err != nil { 102 | return nil, err 103 | } 104 | // 设置需要客户端证书请求,标识需要进行客户端的身份认证 105 | config.ClientAuth = gmtls.RequireAndVerifyClientCert 106 | return config, nil 107 | } 108 | 109 | // 获取 客户端服务端双向身份认证 配置 110 | func bothAuthConfig() (*gmtls.Config, error) { 111 | // 信任的根证书 112 | certPool := x509.NewCertPool() 113 | cacert, err := ioutil.ReadFile(SM2CaCertPath) 114 | if err != nil { 115 | return nil, err 116 | } 117 | certPool.AppendCertsFromPEM(cacert) 118 | authKeypair, err := gmtls.LoadX509KeyPair(SM2AuthCertPath, SM2AuthKeyPath) 119 | if err != nil { 120 | return nil, err 121 | } 122 | return &gmtls.Config{ 123 | GMSupport: &gmtls.GMSupport{}, 124 | RootCAs: certPool, 125 | Certificates: []gmtls.Certificate{authKeypair}, 126 | InsecureSkipVerify: false, 127 | }, nil 128 | 129 | } 130 | 131 | // 获取 单向身份认证(只认证服务端) 配置 132 | func singleSideAuthConfig() (*gmtls.Config, error) { 133 | // 信任的根证书 134 | certPool := x509.NewCertPool() 135 | cacert, err := ioutil.ReadFile(SM2CaCertPath) 136 | if err != nil { 137 | return nil, err 138 | } 139 | certPool.AppendCertsFromPEM(cacert) 140 | 141 | return &gmtls.Config{ 142 | GMSupport: &gmtls.GMSupport{}, 143 | RootCAs: certPool, 144 | }, nil 145 | } 146 | 147 | // 获取 客户端服务端双向身份认证 配置 148 | func rsaBothAuthConfig() (*tls.Config, error) { 149 | // 信任的根证书 150 | certPool := x.NewCertPool() 151 | cacert, err := ioutil.ReadFile(RSACaCertPath) 152 | if err != nil { 153 | return nil, err 154 | } 155 | certPool.AppendCertsFromPEM(cacert) 156 | authKeypair, err := tls.LoadX509KeyPair(RSAAuthCertPath, RSAAuthKeyPath) 157 | if err != nil { 158 | return nil, err 159 | } 160 | return &tls.Config{ 161 | MaxVersion: tls.VersionTLS12, 162 | RootCAs: certPool, 163 | Certificates: []tls.Certificate{authKeypair}, 164 | InsecureSkipVerify: false, 165 | }, nil 166 | 167 | } 168 | 169 | // 获取 单向身份认证(只认证服务端) 配置 170 | func rsaSingleSideAuthConfig() (*tls.Config, error) { 171 | // 信任的根证书 172 | certPool := x.NewCertPool() 173 | cacert, err := ioutil.ReadFile(RSACaCertPath) 174 | if err != nil { 175 | return nil, err 176 | } 177 | certPool.AppendCertsFromPEM(cacert) 178 | 179 | return &tls.Config{ 180 | MaxVersion: tls.VersionTLS12, 181 | RootCAs: certPool, 182 | }, nil 183 | } 184 | -------------------------------------------------------------------------------- /gmtls/auth.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Suzhou Tongji Fintech Research Institute 2017 All Rights Reserved. 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | package gmtls 17 | 18 | import ( 19 | "crypto" 20 | "crypto/ecdsa" 21 | "crypto/rsa" 22 | "encoding/asn1" 23 | "errors" 24 | "fmt" 25 | 26 | "github.com/tjfoc/gmsm/sm2" 27 | ) 28 | 29 | // pickSignatureAlgorithm selects a signature algorithm that is compatible with 30 | // the given public key and the list of algorithms from the peer and this side. 31 | // The lists of signature algorithms (peerSigAlgs and ourSigAlgs) are ignored 32 | // for tlsVersion < VersionTLS12. 33 | // 34 | // The returned SignatureScheme codepoint is only meaningful for TLS 1.2, 35 | // previous TLS versions have a fixed hash function. 36 | func pickSignatureAlgorithm(pubkey crypto.PublicKey, peerSigAlgs, ourSigAlgs []SignatureScheme, tlsVersion uint16) (sigAlg SignatureScheme, sigType uint8, hashFunc crypto.Hash, err error) { 37 | if tlsVersion < VersionTLS12 || len(peerSigAlgs) == 0 { 38 | // For TLS 1.1 and before, the signature algorithm could not be 39 | // negotiated and the hash is fixed based on the signature type. 40 | // For TLS 1.2, if the client didn't send signature_algorithms 41 | // extension then we can assume that it supports SHA1. See 42 | // https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 43 | switch pubkey.(type) { 44 | case *rsa.PublicKey: 45 | if tlsVersion < VersionTLS12 { 46 | return 0, signaturePKCS1v15, crypto.MD5SHA1, nil 47 | } else { 48 | return PKCS1WithSHA1, signaturePKCS1v15, crypto.SHA1, nil 49 | } 50 | case *ecdsa.PublicKey: 51 | return ECDSAWithSHA1, signatureECDSA, crypto.SHA1, nil 52 | case *sm2.PublicKey: 53 | return SM2WITHSM3, signatureSM2, crypto.SHA1, nil 54 | default: 55 | return 0, 0, 0, fmt.Errorf("tls: unsupported public key: %T", pubkey) 56 | } 57 | } 58 | for _, sigAlg := range peerSigAlgs { 59 | if !isSupportedSignatureAlgorithm(sigAlg, ourSigAlgs) { 60 | continue 61 | } 62 | hashAlg, err := lookupTLSHash(sigAlg) 63 | if err != nil { 64 | panic("tls: supported signature algorithm has an unknown hash function") 65 | } 66 | sigType := signatureFromSignatureScheme(sigAlg) 67 | switch pubkey.(type) { 68 | case *rsa.PublicKey: 69 | if sigType == signaturePKCS1v15 || sigType == signatureRSAPSS { 70 | return sigAlg, sigType, hashAlg, nil 71 | } 72 | case *ecdsa.PublicKey: 73 | if sigType == signatureECDSA { 74 | return sigAlg, sigType, hashAlg, nil 75 | } 76 | case *sm2.PublicKey: 77 | if sigType == signatureECDSA { 78 | return sigAlg, sigType, hashAlg, nil 79 | } 80 | default: 81 | return 0, 0, 0, fmt.Errorf("tls: unsupported public key: %T", pubkey) 82 | } 83 | } 84 | return 0, 0, 0, errors.New("tls: peer doesn't support any common signature algorithms") 85 | } 86 | 87 | // verifyHandshakeSignature verifies a signature against pre-hashed handshake 88 | // contents. 89 | func verifyHandshakeSignature(sigType uint8, pubkey crypto.PublicKey, hashFunc crypto.Hash, digest, sig []byte) error { 90 | switch sigType { 91 | case signatureECDSA: 92 | pubKey, ok := pubkey.(*ecdsa.PublicKey) 93 | if !ok { 94 | return errors.New("tls: ECDSA signing requires a ECDSA public key") 95 | } 96 | ecdsaSig := new(ecdsaSignature) 97 | if _, err := asn1.Unmarshal(sig, ecdsaSig); err != nil { 98 | return err 99 | } 100 | if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 { 101 | return errors.New("tls: ECDSA signature contained zero or negative values") 102 | } 103 | if pubKey.Curve == sm2.P256Sm2() { 104 | sm2Public := sm2.PublicKey{ 105 | Curve: pubKey.Curve, 106 | X: pubKey.X, 107 | Y: pubKey.Y, 108 | } 109 | if !sm2Public.Verify(digest, sig) { 110 | return errors.New("tls: SM2 verification failure") 111 | } 112 | } else if !ecdsa.Verify(pubKey, digest, ecdsaSig.R, ecdsaSig.S) { 113 | return errors.New("tls: ECDSA verification failure") 114 | } 115 | case signaturePKCS1v15: 116 | pubKey, ok := pubkey.(*rsa.PublicKey) 117 | if !ok { 118 | return errors.New("tls: RSA signing requires a RSA public key") 119 | } 120 | if err := rsa.VerifyPKCS1v15(pubKey, hashFunc, digest, sig); err != nil { 121 | return err 122 | } 123 | case signatureRSAPSS: 124 | pubKey, ok := pubkey.(*rsa.PublicKey) 125 | if !ok { 126 | return errors.New("tls: RSA signing requires a RSA public key") 127 | } 128 | signOpts := &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash} 129 | if err := rsa.VerifyPSS(pubKey, hashFunc, digest, sig, signOpts); err != nil { 130 | return err 131 | } 132 | case signatureSM2: 133 | pubKey, ok := pubkey.(*sm2.PublicKey) 134 | if !ok { 135 | return errors.New("tls: SM2 signing requires a SM2 public key") 136 | } 137 | if ok := pubKey.Verify(digest, sig); !ok { 138 | return errors.New("verify sm2 signature error") 139 | } 140 | default: 141 | return errors.New("tls: unknown signature algorithm") 142 | } 143 | return nil 144 | } 145 | -------------------------------------------------------------------------------- /gmtls/gmcredentials/echo/echo.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // source: echo.proto 3 | 4 | /* 5 | Package echo is a generated protocol buffer package. 6 | 7 | It is generated from these files: 8 | echo.proto 9 | 10 | It has these top-level messages: 11 | EchoRequest 12 | EchoResponse 13 | */ 14 | package echo 15 | 16 | import proto "github.com/golang/protobuf/proto" 17 | import fmt "fmt" 18 | import math "math" 19 | 20 | import ( 21 | context "golang.org/x/net/context" 22 | grpc "google.golang.org/grpc" 23 | ) 24 | 25 | // Reference imports to suppress errors if they are not otherwise used. 26 | var _ = proto.Marshal 27 | var _ = fmt.Errorf 28 | var _ = math.Inf 29 | 30 | // This is a compile-time assertion to ensure that this generated file 31 | // is compatible with the proto package it is being compiled against. 32 | // A compilation error at this line likely means your copy of the 33 | // proto package needs to be updated. 34 | const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package 35 | 36 | type EchoRequest struct { 37 | Req string `protobuf:"bytes,1,opt,name=req" json:"req,omitempty"` 38 | } 39 | 40 | func (m *EchoRequest) Reset() { *m = EchoRequest{} } 41 | func (m *EchoRequest) String() string { return proto.CompactTextString(m) } 42 | func (*EchoRequest) ProtoMessage() {} 43 | func (*EchoRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } 44 | 45 | func (m *EchoRequest) GetReq() string { 46 | if m != nil { 47 | return m.Req 48 | } 49 | return "" 50 | } 51 | 52 | type EchoResponse struct { 53 | Result string `protobuf:"bytes,1,opt,name=result" json:"result,omitempty"` 54 | } 55 | 56 | func (m *EchoResponse) Reset() { *m = EchoResponse{} } 57 | func (m *EchoResponse) String() string { return proto.CompactTextString(m) } 58 | func (*EchoResponse) ProtoMessage() {} 59 | func (*EchoResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } 60 | 61 | func (m *EchoResponse) GetResult() string { 62 | if m != nil { 63 | return m.Result 64 | } 65 | return "" 66 | } 67 | 68 | func init() { 69 | proto.RegisterType((*EchoRequest)(nil), "echo.EchoRequest") 70 | proto.RegisterType((*EchoResponse)(nil), "echo.EchoResponse") 71 | } 72 | 73 | // Reference imports to suppress errors if they are not otherwise used. 74 | var _ context.Context 75 | var _ grpc.ClientConn 76 | 77 | // This is a compile-time assertion to ensure that this generated file 78 | // is compatible with the grpc package it is being compiled against. 79 | const _ = grpc.SupportPackageIsVersion4 80 | 81 | // Client API for Echo service 82 | 83 | type EchoClient interface { 84 | Echo(ctx context.Context, in *EchoRequest, opts ...grpc.CallOption) (*EchoResponse, error) 85 | } 86 | 87 | type echoClient struct { 88 | cc *grpc.ClientConn 89 | } 90 | 91 | func NewEchoClient(cc *grpc.ClientConn) EchoClient { 92 | return &echoClient{cc} 93 | } 94 | 95 | func (c *echoClient) Echo(ctx context.Context, in *EchoRequest, opts ...grpc.CallOption) (*EchoResponse, error) { 96 | out := new(EchoResponse) 97 | err := grpc.Invoke(ctx, "/echo.Echo/Echo", in, out, c.cc, opts...) 98 | if err != nil { 99 | return nil, err 100 | } 101 | return out, nil 102 | } 103 | 104 | // Server API for Echo service 105 | 106 | type EchoServer interface { 107 | Echo(context.Context, *EchoRequest) (*EchoResponse, error) 108 | } 109 | 110 | func RegisterEchoServer(s *grpc.Server, srv EchoServer) { 111 | s.RegisterService(&_Echo_serviceDesc, srv) 112 | } 113 | 114 | func _Echo_Echo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 115 | in := new(EchoRequest) 116 | if err := dec(in); err != nil { 117 | return nil, err 118 | } 119 | if interceptor == nil { 120 | return srv.(EchoServer).Echo(ctx, in) 121 | } 122 | info := &grpc.UnaryServerInfo{ 123 | Server: srv, 124 | FullMethod: "/echo.Echo/Echo", 125 | } 126 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 127 | return srv.(EchoServer).Echo(ctx, req.(*EchoRequest)) 128 | } 129 | return interceptor(ctx, in, info, handler) 130 | } 131 | 132 | var _Echo_serviceDesc = grpc.ServiceDesc{ 133 | ServiceName: "echo.Echo", 134 | HandlerType: (*EchoServer)(nil), 135 | Methods: []grpc.MethodDesc{ 136 | { 137 | MethodName: "Echo", 138 | Handler: _Echo_Echo_Handler, 139 | }, 140 | }, 141 | Streams: []grpc.StreamDesc{}, 142 | Metadata: "echo.proto", 143 | } 144 | 145 | func init() { proto.RegisterFile("echo.proto", fileDescriptor0) } 146 | 147 | var fileDescriptor0 = []byte{ 148 | // 126 bytes of a gzipped FileDescriptorProto 149 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x4a, 0x4d, 0xce, 0xc8, 150 | 0xd7, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x01, 0xb1, 0x95, 0xe4, 0xb9, 0xb8, 0x5d, 0x93, 151 | 0x33, 0xf2, 0x83, 0x52, 0x0b, 0x4b, 0x53, 0x8b, 0x4b, 0x84, 0x04, 0xb8, 0x98, 0x8b, 0x52, 0x0b, 152 | 0x25, 0x18, 0x15, 0x18, 0x35, 0x38, 0x83, 0x40, 0x4c, 0x25, 0x35, 0x2e, 0x1e, 0x88, 0x82, 0xe2, 153 | 0x82, 0xfc, 0xbc, 0xe2, 0x54, 0x21, 0x31, 0x2e, 0xb6, 0xa2, 0xd4, 0xe2, 0xd2, 0x9c, 0x12, 0xa8, 154 | 0x22, 0x28, 0xcf, 0xc8, 0x9c, 0x8b, 0x05, 0xa4, 0x4e, 0x48, 0x1f, 0x4a, 0x0b, 0xea, 0x81, 0xed, 155 | 0x42, 0x32, 0x5c, 0x4a, 0x08, 0x59, 0x08, 0x62, 0x9c, 0x12, 0x43, 0x12, 0x1b, 0xd8, 0x39, 0xc6, 156 | 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x1b, 0x48, 0x20, 0x0f, 0x9c, 0x00, 0x00, 0x00, 157 | } 158 | -------------------------------------------------------------------------------- /pkcs12/crypto.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package pkcs12 6 | 7 | import ( 8 | "bytes" 9 | "crypto/cipher" 10 | "crypto/des" 11 | "crypto/x509/pkix" 12 | "encoding/asn1" 13 | "errors" 14 | ) 15 | 16 | var ( 17 | oidPBEWithSHAAnd3KeyTripleDESCBC = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 1, 3}) 18 | oidPBEWithSHAAnd40BitRC2CBC = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 1, 6}) 19 | ) 20 | 21 | // pbeCipher is an abstraction of a PKCS#12 cipher. 22 | type pbeCipher interface { 23 | // create returns a cipher.Block given a key. 24 | create(key []byte) (cipher.Block, error) 25 | // deriveKey returns a key derived from the given password and salt. 26 | deriveKey(salt, password []byte, iterations int) []byte 27 | // deriveKey returns an IV derived from the given password and salt. 28 | deriveIV(salt, password []byte, iterations int) []byte 29 | } 30 | 31 | type shaWithTripleDESCBC struct{} 32 | 33 | func (shaWithTripleDESCBC) create(key []byte) (cipher.Block, error) { 34 | return des.NewTripleDESCipher(key) 35 | } 36 | 37 | func (shaWithTripleDESCBC) deriveKey(salt, password []byte, iterations int) []byte { 38 | return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 1, 24) 39 | } 40 | 41 | func (shaWithTripleDESCBC) deriveIV(salt, password []byte, iterations int) []byte { 42 | return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 2, 8) 43 | } 44 | 45 | type shaWith40BitRC2CBC struct{} 46 | 47 | func (shaWith40BitRC2CBC) create(key []byte) (cipher.Block, error) { 48 | return New(key, len(key)*8) 49 | } 50 | 51 | func (shaWith40BitRC2CBC) deriveKey(salt, password []byte, iterations int) []byte { 52 | return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 1, 5) 53 | } 54 | 55 | func (shaWith40BitRC2CBC) deriveIV(salt, password []byte, iterations int) []byte { 56 | return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 2, 8) 57 | } 58 | 59 | type pbeParams struct { 60 | Salt []byte 61 | Iterations int 62 | } 63 | 64 | func pbeCipherFor(algorithm pkix.AlgorithmIdentifier, password []byte) (cipher.Block, []byte, error) { 65 | var cipherType pbeCipher 66 | 67 | switch { 68 | case algorithm.Algorithm.Equal(oidPBEWithSHAAnd3KeyTripleDESCBC): 69 | cipherType = shaWithTripleDESCBC{} 70 | case algorithm.Algorithm.Equal(oidPBEWithSHAAnd40BitRC2CBC): 71 | cipherType = shaWith40BitRC2CBC{} 72 | default: 73 | return nil, nil, NotImplementedError("algorithm " + algorithm.Algorithm.String() + " is not supported") 74 | } 75 | 76 | var params pbeParams 77 | if err := unmarshal(algorithm.Parameters.FullBytes, ¶ms); err != nil { 78 | return nil, nil, err 79 | } 80 | 81 | key := cipherType.deriveKey(params.Salt, password, params.Iterations) 82 | iv := cipherType.deriveIV(params.Salt, password, params.Iterations) 83 | 84 | block, err := cipherType.create(key) 85 | if err != nil { 86 | return nil, nil, err 87 | } 88 | 89 | return block, iv, nil 90 | } 91 | 92 | func pbDecrypterFor(algorithm pkix.AlgorithmIdentifier, password []byte) (cipher.BlockMode, int, error) { 93 | block, iv, err := pbeCipherFor(algorithm, password) 94 | if err != nil { 95 | return nil, 0, err 96 | } 97 | 98 | return cipher.NewCBCDecrypter(block, iv), block.BlockSize(), nil 99 | } 100 | 101 | func pbDecrypt(info decryptable, password []byte) (decrypted []byte, err error) { 102 | cbc, blockSize, err := pbDecrypterFor(info.Algorithm(), password) 103 | if err != nil { 104 | return nil, err 105 | } 106 | 107 | encrypted := info.Data() 108 | if len(encrypted) == 0 { 109 | return nil, errors.New("go-pkcs12: empty encrypted data") 110 | } 111 | if len(encrypted)%blockSize != 0 { 112 | return nil, errors.New("go-pkcs12: input is not a multiple of the block size") 113 | } 114 | decrypted = make([]byte, len(encrypted)) 115 | cbc.CryptBlocks(decrypted, encrypted) 116 | 117 | psLen := int(decrypted[len(decrypted)-1]) 118 | if psLen == 0 || psLen > blockSize { 119 | return nil, ErrDecryption 120 | } 121 | 122 | if len(decrypted) < psLen { 123 | return nil, ErrDecryption 124 | } 125 | ps := decrypted[len(decrypted)-psLen:] 126 | decrypted = decrypted[:len(decrypted)-psLen] 127 | if bytes.Compare(ps, bytes.Repeat([]byte{byte(psLen)}, psLen)) != 0 { 128 | return nil, ErrDecryption 129 | } 130 | 131 | return 132 | } 133 | 134 | // decryptable abstracts a object that contains ciphertext. 135 | type decryptable interface { 136 | Algorithm() pkix.AlgorithmIdentifier 137 | Data() []byte 138 | } 139 | 140 | func pbEncrypterFor(algorithm pkix.AlgorithmIdentifier, password []byte) (cipher.BlockMode, int, error) { 141 | block, iv, err := pbeCipherFor(algorithm, password) 142 | if err != nil { 143 | return nil, 0, err 144 | } 145 | 146 | return cipher.NewCBCEncrypter(block, iv), block.BlockSize(), nil 147 | } 148 | 149 | func pbEncrypt(info encryptable, decrypted []byte, password []byte) error { 150 | cbc, blockSize, err := pbEncrypterFor(info.Algorithm(), password) 151 | if err != nil { 152 | return err 153 | } 154 | 155 | psLen := blockSize - len(decrypted)%blockSize 156 | encrypted := make([]byte, len(decrypted)+psLen) 157 | copy(encrypted[:len(decrypted)], decrypted) 158 | copy(encrypted[len(decrypted):], bytes.Repeat([]byte{byte(psLen)}, psLen)) 159 | cbc.CryptBlocks(encrypted, encrypted) 160 | 161 | info.SetData(encrypted) 162 | 163 | return nil 164 | } 165 | 166 | // encryptable abstracts a object that contains ciphertext. 167 | type encryptable interface { 168 | Algorithm() pkix.AlgorithmIdentifier 169 | SetData([]byte) 170 | } 171 | -------------------------------------------------------------------------------- /sm2/sm2_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Suzhou Tongji Fintech Research Institute 2017 All Rights Reserved. 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | package sm2 17 | 18 | import ( 19 | "bytes" 20 | "crypto/rand" 21 | "fmt" 22 | "io/ioutil" 23 | "math/big" 24 | "os" 25 | "testing" 26 | ) 27 | 28 | func TestSm2(t *testing.T) { 29 | priv, err := GenerateKey(rand.Reader) // 生成密钥对 30 | fmt.Println(priv) 31 | if err != nil { 32 | t.Fatal(err) 33 | } 34 | fmt.Printf("%v\n", priv.Curve.IsOnCurve(priv.X, priv.Y)) // 验证是否为sm2的曲线 35 | pub := &priv.PublicKey 36 | msg := []byte("123456") 37 | d0, err := pub.EncryptAsn1(msg, rand.Reader) 38 | if err != nil { 39 | fmt.Printf("Error: failed to encrypt %s: %v\n", msg, err) 40 | return 41 | } 42 | // fmt.Printf("Cipher text = %v\n", d0) 43 | d1, err := priv.DecryptAsn1(d0) 44 | if err != nil { 45 | fmt.Printf("Error: failed to decrypt: %v\n", err) 46 | } 47 | fmt.Printf("clear text = %s\n", d1) 48 | d2, err := Encrypt(pub, msg, rand.Reader, C1C2C3) 49 | if err != nil { 50 | fmt.Printf("Error: failed to encrypt %s: %v\n", msg, err) 51 | return 52 | } 53 | // fmt.Printf("Cipher text = %v\n", d0) 54 | d3, err := Decrypt(priv, d2, C1C2C3) 55 | if err != nil { 56 | fmt.Printf("Error: failed to decrypt: %v\n", err) 57 | } 58 | fmt.Printf("clear text = %s\n", d3) 59 | msg, _ = ioutil.ReadFile("ifile") // 从文件读取数据 60 | sign, err := priv.Sign(rand.Reader, msg, nil) // 签名 61 | if err != nil { 62 | t.Fatal(err) 63 | } 64 | 65 | err = ioutil.WriteFile("TestResult", sign, os.FileMode(0644)) 66 | if err != nil { 67 | t.Fatal(err) 68 | } 69 | signdata, _ := ioutil.ReadFile("TestResult") 70 | ok := priv.PublicKey.Verify(msg, signdata) // 密钥验证 71 | if ok != true { 72 | fmt.Printf("Verify error\n") 73 | } else { 74 | fmt.Printf("Verify ok\n") 75 | } 76 | pubKey := priv.PublicKey 77 | ok = pubKey.Verify(msg, signdata) // 公钥验证 78 | if ok != true { 79 | fmt.Printf("Verify error\n") 80 | } else { 81 | fmt.Printf("Verify ok\n") 82 | } 83 | 84 | } 85 | 86 | func BenchmarkSM2(t *testing.B) { 87 | t.ReportAllocs() 88 | msg := []byte("test") 89 | priv, err := GenerateKey(nil) // 生成密钥对 90 | if err != nil { 91 | t.Fatal(err) 92 | } 93 | t.ResetTimer() 94 | for i := 0; i < t.N; i++ { 95 | sign, err := priv.Sign(nil, msg, nil) // 签名 96 | if err != nil { 97 | t.Fatal(err) 98 | } 99 | priv.PublicKey.Verify(msg, sign) // 密钥验证 100 | } 101 | } 102 | 103 | func TestKEB2(t *testing.T) { 104 | ida := []byte{'1', '2', '3', '4', '5', '6', '7', '8', 105 | '1', '2', '3', '4', '5', '6', '7', '8'} 106 | idb := []byte{'1', '2', '3', '4', '5', '6', '7', '8', 107 | '1', '2', '3', '4', '5', '6', '7', '8'} 108 | daBuf := []byte{0x81, 0xEB, 0x26, 0xE9, 0x41, 0xBB, 0x5A, 0xF1, 109 | 0x6D, 0xF1, 0x16, 0x49, 0x5F, 0x90, 0x69, 0x52, 110 | 0x72, 0xAE, 0x2C, 0xD6, 0x3D, 0x6C, 0x4A, 0xE1, 111 | 0x67, 0x84, 0x18, 0xBE, 0x48, 0x23, 0x00, 0x29} 112 | dbBuf := []byte{0x78, 0x51, 0x29, 0x91, 0x7D, 0x45, 0xA9, 0xEA, 113 | 0x54, 0x37, 0xA5, 0x93, 0x56, 0xB8, 0x23, 0x38, 114 | 0xEA, 0xAD, 0xDA, 0x6C, 0xEB, 0x19, 0x90, 0x88, 115 | 0xF1, 0x4A, 0xE1, 0x0D, 0xEF, 0xA2, 0x29, 0xB5} 116 | raBuf := []byte{0xD4, 0xDE, 0x15, 0x47, 0x4D, 0xB7, 0x4D, 0x06, 117 | 0x49, 0x1C, 0x44, 0x0D, 0x30, 0x5E, 0x01, 0x24, 118 | 0x00, 0x99, 0x0F, 0x3E, 0x39, 0x0C, 0x7E, 0x87, 119 | 0x15, 0x3C, 0x12, 0xDB, 0x2E, 0xA6, 0x0B, 0xB3} 120 | 121 | rbBuf := []byte{0x7E, 0x07, 0x12, 0x48, 0x14, 0xB3, 0x09, 0x48, 122 | 0x91, 0x25, 0xEA, 0xED, 0x10, 0x11, 0x13, 0x16, 123 | 0x4E, 0xBF, 0x0F, 0x34, 0x58, 0xC5, 0xBD, 0x88, 124 | 0x33, 0x5C, 0x1F, 0x9D, 0x59, 0x62, 0x43, 0xD6} 125 | 126 | expk := []byte{0x6C, 0x89, 0x34, 0x73, 0x54, 0xDE, 0x24, 0x84, 127 | 0xC6, 0x0B, 0x4A, 0xB1, 0xFD, 0xE4, 0xC6, 0xE5} 128 | 129 | curve := P256Sm2() 130 | curve.ScalarBaseMult(daBuf) 131 | da := new(PrivateKey) 132 | da.PublicKey.Curve = curve 133 | da.D = new(big.Int).SetBytes(daBuf) 134 | da.PublicKey.X, da.PublicKey.Y = curve.ScalarBaseMult(daBuf) 135 | 136 | db := new(PrivateKey) 137 | db.PublicKey.Curve = curve 138 | db.D = new(big.Int).SetBytes(dbBuf) 139 | db.PublicKey.X, db.PublicKey.Y = curve.ScalarBaseMult(dbBuf) 140 | 141 | ra := new(PrivateKey) 142 | ra.PublicKey.Curve = curve 143 | ra.D = new(big.Int).SetBytes(raBuf) 144 | ra.PublicKey.X, ra.PublicKey.Y = curve.ScalarBaseMult(raBuf) 145 | 146 | rb := new(PrivateKey) 147 | rb.PublicKey.Curve = curve 148 | rb.D = new(big.Int).SetBytes(rbBuf) 149 | rb.PublicKey.X, rb.PublicKey.Y = curve.ScalarBaseMult(rbBuf) 150 | 151 | k1, Sb, S2, err := KeyExchangeB(16, ida, idb, db, &da.PublicKey, rb, &ra.PublicKey) 152 | if err != nil { 153 | t.Error(err) 154 | } 155 | k2, S1, Sa, err := KeyExchangeA(16, ida, idb, da, &db.PublicKey, ra, &rb.PublicKey) 156 | if err != nil { 157 | t.Error(err) 158 | } 159 | if bytes.Compare(k1, k2) != 0 { 160 | t.Error("key exchange differ") 161 | } 162 | if bytes.Compare(k1, expk) != 0 { 163 | t.Errorf("expected %x, found %x", expk, k1) 164 | } 165 | if bytes.Compare(S1, Sb) != 0 { 166 | t.Error("hash verfication failed") 167 | } 168 | if bytes.Compare(Sa, S2) != 0 { 169 | t.Error("hash verfication failed") 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /gmtls/ticket.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Suzhou Tongji Fintech Research Institute 2017 All Rights Reserved. 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | package gmtls 17 | 18 | import ( 19 | "bytes" 20 | "crypto/aes" 21 | "crypto/cipher" 22 | "crypto/hmac" 23 | "crypto/sha256" 24 | "crypto/subtle" 25 | "errors" 26 | "io" 27 | ) 28 | 29 | // sessionState contains the information that is serialized into a session 30 | // ticket in order to later resume a connection. 31 | type sessionState struct { 32 | vers uint16 33 | cipherSuite uint16 34 | masterSecret []byte 35 | certificates [][]byte 36 | // usedOldKey is true if the ticket from which this session came from 37 | // was encrypted with an older key and thus should be refreshed. 38 | usedOldKey bool 39 | } 40 | 41 | func (s *sessionState) equal(i interface{}) bool { 42 | s1, ok := i.(*sessionState) 43 | if !ok { 44 | return false 45 | } 46 | 47 | if s.vers != s1.vers || 48 | s.cipherSuite != s1.cipherSuite || 49 | !bytes.Equal(s.masterSecret, s1.masterSecret) { 50 | return false 51 | } 52 | 53 | if len(s.certificates) != len(s1.certificates) { 54 | return false 55 | } 56 | 57 | for i := range s.certificates { 58 | if !bytes.Equal(s.certificates[i], s1.certificates[i]) { 59 | return false 60 | } 61 | } 62 | 63 | return true 64 | } 65 | 66 | func (s *sessionState) marshal() []byte { 67 | length := 2 + 2 + 2 + len(s.masterSecret) + 2 68 | for _, cert := range s.certificates { 69 | length += 4 + len(cert) 70 | } 71 | 72 | ret := make([]byte, length) 73 | x := ret 74 | x[0] = byte(s.vers >> 8) 75 | x[1] = byte(s.vers) 76 | x[2] = byte(s.cipherSuite >> 8) 77 | x[3] = byte(s.cipherSuite) 78 | x[4] = byte(len(s.masterSecret) >> 8) 79 | x[5] = byte(len(s.masterSecret)) 80 | x = x[6:] 81 | copy(x, s.masterSecret) 82 | x = x[len(s.masterSecret):] 83 | 84 | x[0] = byte(len(s.certificates) >> 8) 85 | x[1] = byte(len(s.certificates)) 86 | x = x[2:] 87 | 88 | for _, cert := range s.certificates { 89 | x[0] = byte(len(cert) >> 24) 90 | x[1] = byte(len(cert) >> 16) 91 | x[2] = byte(len(cert) >> 8) 92 | x[3] = byte(len(cert)) 93 | copy(x[4:], cert) 94 | x = x[4+len(cert):] 95 | } 96 | 97 | return ret 98 | } 99 | 100 | func (s *sessionState) unmarshal(data []byte) bool { 101 | if len(data) < 8 { 102 | return false 103 | } 104 | 105 | s.vers = uint16(data[0])<<8 | uint16(data[1]) 106 | s.cipherSuite = uint16(data[2])<<8 | uint16(data[3]) 107 | masterSecretLen := int(data[4])<<8 | int(data[5]) 108 | data = data[6:] 109 | if len(data) < masterSecretLen { 110 | return false 111 | } 112 | 113 | s.masterSecret = data[:masterSecretLen] 114 | data = data[masterSecretLen:] 115 | 116 | if len(data) < 2 { 117 | return false 118 | } 119 | 120 | numCerts := int(data[0])<<8 | int(data[1]) 121 | data = data[2:] 122 | 123 | s.certificates = make([][]byte, numCerts) 124 | for i := range s.certificates { 125 | if len(data) < 4 { 126 | return false 127 | } 128 | certLen := int(data[0])<<24 | int(data[1])<<16 | int(data[2])<<8 | int(data[3]) 129 | data = data[4:] 130 | if certLen < 0 { 131 | return false 132 | } 133 | if len(data) < certLen { 134 | return false 135 | } 136 | s.certificates[i] = data[:certLen] 137 | data = data[certLen:] 138 | } 139 | 140 | return len(data) == 0 141 | } 142 | 143 | func (c *Conn) encryptTicket(state *sessionState) ([]byte, error) { 144 | serialized := state.marshal() 145 | encrypted := make([]byte, ticketKeyNameLen+aes.BlockSize+len(serialized)+sha256.Size) 146 | keyName := encrypted[:ticketKeyNameLen] 147 | iv := encrypted[ticketKeyNameLen : ticketKeyNameLen+aes.BlockSize] 148 | macBytes := encrypted[len(encrypted)-sha256.Size:] 149 | 150 | if _, err := io.ReadFull(c.config.rand(), iv); err != nil { 151 | return nil, err 152 | } 153 | key := c.config.ticketKeys()[0] 154 | copy(keyName, key.keyName[:]) 155 | block, err := aes.NewCipher(key.aesKey[:]) 156 | if err != nil { 157 | return nil, errors.New("tls: failed to create cipher while encrypting ticket: " + err.Error()) 158 | } 159 | cipher.NewCTR(block, iv).XORKeyStream(encrypted[ticketKeyNameLen+aes.BlockSize:], serialized) 160 | 161 | mac := hmac.New(sha256.New, key.hmacKey[:]) 162 | mac.Write(encrypted[:len(encrypted)-sha256.Size]) 163 | mac.Sum(macBytes[:0]) 164 | 165 | return encrypted, nil 166 | } 167 | 168 | func (c *Conn) decryptTicket(encrypted []byte) (*sessionState, bool) { 169 | if c.config.SessionTicketsDisabled || 170 | len(encrypted) < ticketKeyNameLen+aes.BlockSize+sha256.Size { 171 | return nil, false 172 | } 173 | 174 | keyName := encrypted[:ticketKeyNameLen] 175 | iv := encrypted[ticketKeyNameLen : ticketKeyNameLen+aes.BlockSize] 176 | macBytes := encrypted[len(encrypted)-sha256.Size:] 177 | 178 | keys := c.config.ticketKeys() 179 | keyIndex := -1 180 | for i, candidateKey := range keys { 181 | if bytes.Equal(keyName, candidateKey.keyName[:]) { 182 | keyIndex = i 183 | break 184 | } 185 | } 186 | 187 | if keyIndex == -1 { 188 | return nil, false 189 | } 190 | key := &keys[keyIndex] 191 | 192 | mac := hmac.New(sha256.New, key.hmacKey[:]) 193 | mac.Write(encrypted[:len(encrypted)-sha256.Size]) 194 | expected := mac.Sum(nil) 195 | 196 | if subtle.ConstantTimeCompare(macBytes, expected) != 1 { 197 | return nil, false 198 | } 199 | 200 | block, err := aes.NewCipher(key.aesKey[:]) 201 | if err != nil { 202 | return nil, false 203 | } 204 | ciphertext := encrypted[ticketKeyNameLen+aes.BlockSize : len(encrypted)-sha256.Size] 205 | plaintext := ciphertext 206 | cipher.NewCTR(block, iv).XORKeyStream(plaintext, ciphertext) 207 | 208 | state := &sessionState{usedOldKey: keyIndex > 0} 209 | ok := state.unmarshal(plaintext) 210 | return state, ok 211 | } 212 | -------------------------------------------------------------------------------- /pkcs12/pbkdf.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package pkcs12 6 | 7 | import ( 8 | "bytes" 9 | "crypto/sha1" 10 | "math/big" 11 | ) 12 | 13 | var ( 14 | one = big.NewInt(1) 15 | ) 16 | 17 | // sha1Sum returns the SHA-1 hash of in. 18 | func sha1Sum(in []byte) []byte { 19 | sum := sha1.Sum(in) 20 | return sum[:] 21 | } 22 | 23 | // fillWithRepeats returns v*ceiling(len(pattern) / v) bytes consisting of 24 | // repeats of pattern. 25 | func fillWithRepeats(pattern []byte, v int) []byte { 26 | if len(pattern) == 0 { 27 | return nil 28 | } 29 | outputLen := v * ((len(pattern) + v - 1) / v) 30 | return bytes.Repeat(pattern, (outputLen+len(pattern)-1)/len(pattern))[:outputLen] 31 | } 32 | 33 | func pbkdf(hash func([]byte) []byte, u, v int, salt, password []byte, r int, ID byte, size int) (key []byte) { 34 | // implementation of https://tools.ietf.org/html/rfc7292#appendix-B.2 , RFC text verbatim in comments 35 | 36 | // Let H be a hash function built around a compression function f: 37 | 38 | // Z_2^u x Z_2^v -> Z_2^u 39 | 40 | // (that is, H has a chaining variable and output of length u bits, and 41 | // the message input to the compression function of H is v bits). The 42 | // values for u and v are as follows: 43 | 44 | // HASH FUNCTION VALUE u VALUE v 45 | // MD2, MD5 128 512 46 | // SHA-1 160 512 47 | // SHA-224 224 512 48 | // SHA-256 256 512 49 | // SHA-384 384 1024 50 | // SHA-512 512 1024 51 | // SHA-512/224 224 1024 52 | // SHA-512/256 256 1024 53 | 54 | // Furthermore, let r be the iteration count. 55 | 56 | // We assume here that u and v are both multiples of 8, as are the 57 | // lengths of the password and salt strings (which we denote by p and s, 58 | // respectively) and the number n of pseudorandom bits required. In 59 | // addition, u and v are of course non-zero. 60 | 61 | // For information on security considerations for MD5 [19], see [25] and 62 | // [1], and on those for MD2, see [18]. 63 | 64 | // The following procedure can be used to produce pseudorandom bits for 65 | // a particular "purpose" that is identified by a byte called "ID". 66 | // This standard specifies 3 different values for the ID byte: 67 | 68 | // 1. If ID=1, then the pseudorandom bits being produced are to be used 69 | // as key material for performing encryption or decryption. 70 | 71 | // 2. If ID=2, then the pseudorandom bits being produced are to be used 72 | // as an IV (Initial Value) for encryption or decryption. 73 | 74 | // 3. If ID=3, then the pseudorandom bits being produced are to be used 75 | // as an integrity key for MACing. 76 | 77 | // 1. Construct a string, D (the "diversifier"), by concatenating v/8 78 | // copies of ID. 79 | var D []byte 80 | for i := 0; i < v; i++ { 81 | D = append(D, ID) 82 | } 83 | 84 | // 2. Concatenate copies of the salt together to create a string S of 85 | // length v(ceiling(s/v)) bits (the final copy of the salt may be 86 | // truncated to create S). Note that if the salt is the empty 87 | // string, then so is S. 88 | 89 | S := fillWithRepeats(salt, v) 90 | 91 | // 3. Concatenate copies of the password together to create a string P 92 | // of length v(ceiling(p/v)) bits (the final copy of the password 93 | // may be truncated to create P). Note that if the password is the 94 | // empty string, then so is P. 95 | 96 | P := fillWithRepeats(password, v) 97 | 98 | // 4. Set I=S||P to be the concatenation of S and P. 99 | I := append(S, P...) 100 | 101 | // 5. Set c=ceiling(n/u). 102 | c := (size + u - 1) / u 103 | 104 | // 6. For i=1, 2, ..., c, do the following: 105 | A := make([]byte, c*20) 106 | var IjBuf []byte 107 | for i := 0; i < c; i++ { 108 | // A. Set A2=H^r(D||I). (i.e., the r-th hash of D||1, 109 | // H(H(H(... H(D||I)))) 110 | Ai := hash(append(D, I...)) 111 | for j := 1; j < r; j++ { 112 | Ai = hash(Ai) 113 | } 114 | copy(A[i*20:], Ai[:]) 115 | 116 | if i < c-1 { // skip on last iteration 117 | // B. Concatenate copies of Ai to create a string B of length v 118 | // bits (the final copy of Ai may be truncated to create B). 119 | var B []byte 120 | for len(B) < v { 121 | B = append(B, Ai[:]...) 122 | } 123 | B = B[:v] 124 | 125 | // C. Treating I as a concatenation I_0, I_1, ..., I_(k-1) of v-bit 126 | // blocks, where k=ceiling(s/v)+ceiling(p/v), modify I by 127 | // setting I_j=(I_j+B+1) mod 2^v for each j. 128 | { 129 | Bbi := new(big.Int).SetBytes(B) 130 | Ij := new(big.Int) 131 | 132 | for j := 0; j < len(I)/v; j++ { 133 | Ij.SetBytes(I[j*v : (j+1)*v]) 134 | Ij.Add(Ij, Bbi) 135 | Ij.Add(Ij, one) 136 | Ijb := Ij.Bytes() 137 | // We expect Ijb to be exactly v bytes, 138 | // if it is longer or shorter we must 139 | // adjust it accordingly. 140 | if len(Ijb) > v { 141 | Ijb = Ijb[len(Ijb)-v:] 142 | } 143 | if len(Ijb) < v { 144 | if IjBuf == nil { 145 | IjBuf = make([]byte, v) 146 | } 147 | bytesShort := v - len(Ijb) 148 | for i := 0; i < bytesShort; i++ { 149 | IjBuf[i] = 0 150 | } 151 | copy(IjBuf[bytesShort:], Ijb) 152 | Ijb = IjBuf 153 | } 154 | copy(I[j*v:(j+1)*v], Ijb) 155 | } 156 | } 157 | } 158 | } 159 | // 7. Concatenate A_1, A_2, ..., A_c together to form a pseudorandom 160 | // bit string, A. 161 | 162 | // 8. Use the first n bits of A as the output of this entire process. 163 | return A[:size] 164 | 165 | // If the above process is being used to generate a DES key, the process 166 | // should be used to create 64 random bits, and the key's parity bits 167 | // should be set after the 64 bits have been produced. Similar concerns 168 | // hold for 2-key and 3-key triple-DES keys, for CDMF keys, and for any 169 | // similar keys with parity bits "built into them". 170 | } 171 | -------------------------------------------------------------------------------- /gmtls/http_client_test.go: -------------------------------------------------------------------------------- 1 | package gmtls 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "testing" 9 | "time" 10 | 11 | "github.com/tjfoc/gmsm/x509" 12 | ) 13 | 14 | var _ExpectRawContent = []byte("Hello World!") 15 | 16 | // 启动HTTP测试服务器 17 | func bootHttpServer(t *testing.T) { 18 | serveMux := http.NewServeMux() 19 | serveMux.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) { 20 | _, _ = writer.Write(_ExpectRawContent) 21 | }) 22 | fmt.Println(">> HTTP :50053 running...") 23 | err := http.ListenAndServe(":50053", serveMux) 24 | if err != nil { 25 | t.Fatal(err) 26 | } 27 | } 28 | 29 | // 启动GM HTTPS测试服务器 30 | func bootGMHTTPSServer(t *testing.T) { 31 | sigCert, err := LoadX509KeyPair( 32 | "websvr/certs/sm2_sign_cert.cer", 33 | "websvr/certs/sm2_sign_key.pem") 34 | if err != nil { 35 | t.Fatal(err) 36 | } 37 | encCert, err := LoadX509KeyPair( 38 | "websvr/certs/sm2_enc_cert.cer", 39 | "websvr/certs/sm2_enc_key.pem") 40 | if err != nil { 41 | t.Fatal(err) 42 | } 43 | config := &Config{ 44 | GMSupport: &GMSupport{}, 45 | Certificates: []Certificate{sigCert, encCert}, 46 | InsecureSkipVerify: true, 47 | } 48 | if err != nil { 49 | panic(err) 50 | } 51 | 52 | ln, err := Listen("tcp", ":50054", config) 53 | if err != nil { 54 | t.Fatal(err) 55 | } 56 | defer ln.Close() 57 | serveMux := http.NewServeMux() 58 | serveMux.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) { 59 | _, _ = writer.Write(_ExpectRawContent) 60 | }) 61 | fmt.Println(">> HTTP :50054 [GMSSL] running...") 62 | err = http.Serve(ln, serveMux) 63 | if err != nil { 64 | t.Fatal(err) 65 | } 66 | } 67 | 68 | // 启动GM HTTPS测试服务器 双向身份认证 69 | func bootGMAuthHTTPSServer(t *testing.T) { 70 | sigCert, err := LoadX509KeyPair( 71 | "websvr/certs/sm2_sign_cert.cer", 72 | "websvr/certs/sm2_sign_key.pem") 73 | if err != nil { 74 | t.Fatal(err) 75 | } 76 | encCert, err := LoadX509KeyPair( 77 | "websvr/certs/sm2_enc_cert.cer", 78 | "websvr/certs/sm2_enc_key.pem") 79 | if err != nil { 80 | t.Fatal(err) 81 | } 82 | 83 | certPool := x509.NewCertPool() 84 | cacert, err := ioutil.ReadFile("websvr/certs/SM2_CA.cer") 85 | if err != nil { 86 | t.Fatal(err) 87 | } 88 | certPool.AppendCertsFromPEM(cacert) 89 | 90 | config := &Config{ 91 | GMSupport: &GMSupport{}, 92 | Certificates: []Certificate{sigCert, encCert}, 93 | ClientAuth: RequireAndVerifyClientCert, 94 | ClientCAs: certPool, 95 | } 96 | if err != nil { 97 | panic(err) 98 | } 99 | 100 | ln, err := Listen("tcp", ":50055", config) 101 | if err != nil { 102 | t.Fatal(err) 103 | } 104 | defer ln.Close() 105 | serveMux := http.NewServeMux() 106 | serveMux.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) { 107 | _, _ = writer.Write(_ExpectRawContent) 108 | }) 109 | fmt.Println(">> HTTP :50055 [GMSSL] Client Auth running...") 110 | err = http.Serve(ln, serveMux) 111 | if err != nil { 112 | t.Fatal(err) 113 | } 114 | } 115 | 116 | // HTTP 客户端连接测试 117 | func TestSimpleNewHTTPSClient1(t *testing.T) { 118 | go bootHttpServer(t) 119 | //go bootGMHTTPSServer(t) 120 | /* 121 | HTTP 连接测试 122 | */ 123 | time.Sleep(time.Second) 124 | httpClient := NewCustomHTTPSClient(nil) 125 | response, err := httpClient.Get("http://localhost:50053") 126 | if err != nil { 127 | t.Fatal(err) 128 | } 129 | defer response.Body.Close() 130 | raw, err := ioutil.ReadAll(response.Body) 131 | if err != nil { 132 | t.Fatal(err) 133 | } 134 | if !bytes.Equal(raw, _ExpectRawContent) { 135 | t.Fatalf(">> HTTP响应内容与期待内容不符, expect %s, actual: %s", string(_ExpectRawContent), string(raw)) 136 | } 137 | } 138 | 139 | // GM HTTPS 客户端连接测试 140 | func TestNewHTTPSClient2(t *testing.T) { 141 | go bootGMHTTPSServer(t) 142 | /* 143 | GM HTTPS 连接测试 144 | */ 145 | time.Sleep(time.Second) 146 | // 信任的根证书 147 | 148 | config, err := createClientGMTLSConfig("", "", []string{"websvr/certs/SM2_CA.cer"}) 149 | if err != nil { 150 | t.Fatal(err) 151 | } 152 | httpClient := NewCustomHTTPSClient(config) 153 | response, err := httpClient.Get("https://localhost:50054") 154 | if err != nil { 155 | t.Fatal(err) 156 | } 157 | defer response.Body.Close() 158 | raw, err := ioutil.ReadAll(response.Body) 159 | if err != nil { 160 | t.Fatal(err) 161 | } 162 | if !bytes.Equal(raw, _ExpectRawContent) { 163 | t.Fatalf(">> GM HTTPS响应内容与期待内容不符, expect %s, actual: %s", string(_ExpectRawContent), string(raw)) 164 | } 165 | } 166 | 167 | // GM HTTPS 客户端连接测试 双向身份认证 168 | func TestNewHTTPSClient3(t *testing.T) { 169 | go bootGMAuthHTTPSServer(t) 170 | /* 171 | GM HTTPS 双向身份认证 172 | */ 173 | time.Sleep(time.Second) 174 | 175 | config, err := createClientGMTLSConfig("websvr/certs/sm2_auth_key.pem", "websvr/certs/sm2_auth_cert.cer", []string{"websvr/certs/SM2_CA.cer"}) 176 | if err != nil { 177 | t.Fatal(err) 178 | } 179 | httpClient := NewCustomHTTPSClient(config) 180 | 181 | response, err := httpClient.Get("https://localhost:50055") 182 | if err != nil { 183 | t.Fatal(err) 184 | } 185 | defer response.Body.Close() 186 | raw, err := ioutil.ReadAll(response.Body) 187 | if err != nil { 188 | t.Fatal(err) 189 | } 190 | if !bytes.Equal(raw, _ExpectRawContent) { 191 | t.Fatalf(">> GM HTTPS响应内容与期待内容不符, expect %s, actual: %s", string(_ExpectRawContent), string(raw)) 192 | } 193 | } 194 | 195 | func createClientGMTLSConfig(keyPath string, certPath string, caPaths []string) (*Config, error) { 196 | 197 | cfg := &Config{ 198 | GMSupport: &GMSupport{}, 199 | } 200 | cfg.Certificates = []Certificate{} 201 | if keyPath != "" && certPath != "" { 202 | cert, err := LoadX509KeyPair(certPath, keyPath) 203 | if err != nil { 204 | return nil, fmt.Errorf("load gm X509 keyPair error: %v", err) 205 | } 206 | cfg.Certificates = append(cfg.Certificates, cert) 207 | } 208 | 209 | var pool *x509.CertPool = nil 210 | if len(caPaths) > 0 { 211 | pool = x509.NewCertPool() 212 | for _, certPath := range caPaths { 213 | caCrt, err := ioutil.ReadFile(certPath) 214 | if err != nil { 215 | return nil, err 216 | } 217 | ok := pool.AppendCertsFromPEM(caCrt) 218 | if !ok { 219 | return nil, fmt.Errorf("append cert to pool fail at %s", certPath) 220 | } 221 | } 222 | } 223 | 224 | cfg.MinVersion = VersionGMSSL 225 | cfg.MaxVersion = VersionTLS12 226 | 227 | cfg.PreferServerCipherSuites = true 228 | // cfg.CipherSuites use default value []uint16{GMTLS_SM2_WITH_SM4_SM3, GMTLS_ECDHE_SM2_WITH_SM4_SM3} 229 | 230 | cfg.RootCAs = pool 231 | // cfg.ServerName = "localhost" 232 | cfg.InsecureSkipVerify = false 233 | 234 | return cfg, nil 235 | 236 | } 237 | -------------------------------------------------------------------------------- /x509/cert_pool.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Suzhou Tongji Fintech Research Institute 2017 All Rights Reserved. 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | package x509 17 | 18 | import ( 19 | "encoding/pem" 20 | "errors" 21 | "io/ioutil" 22 | "os" 23 | "runtime" 24 | "sync" 25 | ) 26 | 27 | // Possible certificate files; stop after finding one. 28 | var certFiles = []string{ 29 | "/etc/ssl/certs/ca-certificates.crt", // Debian/Ubuntu/Gentoo etc. 30 | "/etc/pki/tls/certs/ca-bundle.crt", // Fedora/RHEL 6 31 | "/etc/ssl/ca-bundle.pem", // OpenSUSE 32 | "/etc/pki/tls/cacert.pem", // OpenELEC 33 | "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", // CentOS/RHEL 7 34 | } 35 | 36 | // CertPool is a set of certificates. 37 | type CertPool struct { 38 | bySubjectKeyId map[string][]int 39 | byName map[string][]int 40 | certs []*Certificate 41 | } 42 | 43 | // NewCertPool returns a new, empty CertPool. 44 | func NewCertPool() *CertPool { 45 | return &CertPool{ 46 | bySubjectKeyId: make(map[string][]int), 47 | byName: make(map[string][]int), 48 | } 49 | } 50 | 51 | // Possible directories with certificate files; stop after successfully 52 | // reading at least one file from a directory. 53 | var certDirectories = []string{ 54 | "/etc/ssl/certs", // SLES10/SLES11, https://golang.org/issue/12139 55 | "/system/etc/security/cacerts", // Android 56 | } 57 | 58 | var ( 59 | once sync.Once 60 | systemRoots *CertPool 61 | systemRootsErr error 62 | ) 63 | 64 | func systemRootsPool() *CertPool { 65 | once.Do(initSystemRoots) 66 | return systemRoots 67 | } 68 | 69 | func initSystemRoots() { 70 | systemRoots, systemRootsErr = loadSystemRoots() 71 | } 72 | 73 | func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) { 74 | return nil, nil 75 | } 76 | 77 | func loadSystemRoots() (*CertPool, error) { 78 | roots := NewCertPool() 79 | var firstErr error 80 | for _, file := range certFiles { 81 | data, err := ioutil.ReadFile(file) 82 | if err == nil { 83 | roots.AppendCertsFromPEM(data) 84 | return roots, nil 85 | } 86 | if firstErr == nil && !os.IsNotExist(err) { 87 | firstErr = err 88 | } 89 | } 90 | 91 | for _, directory := range certDirectories { 92 | fis, err := ioutil.ReadDir(directory) 93 | if err != nil { 94 | if firstErr == nil && !os.IsNotExist(err) { 95 | firstErr = err 96 | } 97 | continue 98 | } 99 | rootsAdded := false 100 | for _, fi := range fis { 101 | data, err := ioutil.ReadFile(directory + "/" + fi.Name()) 102 | if err == nil && roots.AppendCertsFromPEM(data) { 103 | rootsAdded = true 104 | } 105 | } 106 | if rootsAdded { 107 | return roots, nil 108 | } 109 | } 110 | 111 | return nil, firstErr 112 | } 113 | 114 | // SystemCertPool returns a copy of the system cert pool. 115 | // 116 | // Any mutations to the returned pool are not written to disk and do 117 | // not affect any other pool. 118 | func SystemCertPool() (*CertPool, error) { 119 | if runtime.GOOS == "windows" { 120 | // Issue 16736, 18609: 121 | return nil, errors.New("crypto/x509: system root pool is not available on Windows") 122 | } 123 | 124 | return loadSystemRoots() 125 | } 126 | 127 | // findVerifiedParents attempts to find certificates in s which have signed the 128 | // given certificate. If any candidates were rejected then errCert will be set 129 | // to one of them, arbitrarily, and err will contain the reason that it was 130 | // rejected. 131 | func (s *CertPool) findVerifiedParents(cert *Certificate) (parents []int, errCert *Certificate, err error) { 132 | if s == nil { 133 | return 134 | } 135 | var candidates []int 136 | 137 | if len(cert.AuthorityKeyId) > 0 { 138 | candidates = s.bySubjectKeyId[string(cert.AuthorityKeyId)] 139 | } 140 | if len(candidates) == 0 { 141 | candidates = s.byName[string(cert.RawIssuer)] 142 | } 143 | 144 | for _, c := range candidates { 145 | if err = cert.CheckSignatureFrom(s.certs[c]); err == nil { 146 | parents = append(parents, c) 147 | } else { 148 | errCert = s.certs[c] 149 | } 150 | } 151 | 152 | return 153 | } 154 | 155 | func (s *CertPool) contains(cert *Certificate) bool { 156 | if s == nil { 157 | return false 158 | } 159 | 160 | candidates := s.byName[string(cert.RawSubject)] 161 | for _, c := range candidates { 162 | if s.certs[c].Equal(cert) { 163 | return true 164 | } 165 | } 166 | 167 | return false 168 | } 169 | 170 | // AddCert adds a certificate to a pool. 171 | func (s *CertPool) AddCert(cert *Certificate) { 172 | if cert == nil { 173 | panic("adding nil Certificate to CertPool") 174 | } 175 | 176 | // Check that the certificate isn't being added twice. 177 | if s.contains(cert) { 178 | return 179 | } 180 | 181 | n := len(s.certs) 182 | s.certs = append(s.certs, cert) 183 | 184 | if len(cert.SubjectKeyId) > 0 { 185 | keyId := string(cert.SubjectKeyId) 186 | s.bySubjectKeyId[keyId] = append(s.bySubjectKeyId[keyId], n) 187 | } 188 | name := string(cert.RawSubject) 189 | s.byName[name] = append(s.byName[name], n) 190 | } 191 | 192 | // AppendCertsFromPEM attempts to parse a series of PEM encoded certificates. 193 | // It appends any certificates found to s and reports whether any certificates 194 | // were successfully parsed. 195 | // 196 | // On many Linux systems, /etc/ssl/cert.pem will contain the system wide set 197 | // of root CAs in a format suitable for this function. 198 | func (s *CertPool) AppendCertsFromPEM(pemCerts []byte) (ok bool) { 199 | for len(pemCerts) > 0 { 200 | var block *pem.Block 201 | block, pemCerts = pem.Decode(pemCerts) 202 | if block == nil { 203 | break 204 | } 205 | if block.Type != "CERTIFICATE" || len(block.Headers) != 0 { 206 | continue 207 | } 208 | 209 | cert, err := ParseCertificate(block.Bytes) 210 | if err != nil { 211 | continue 212 | } 213 | 214 | s.AddCert(cert) 215 | ok = true 216 | } 217 | 218 | return 219 | } 220 | 221 | // Subjects returns a list of the DER-encoded subjects of 222 | // all of the certificates in the pool. 223 | func (s *CertPool) Subjects() [][]byte { 224 | res := make([][]byte, len(s.certs)) 225 | for i, c := range s.certs { 226 | res[i] = c.RawSubject 227 | } 228 | return res 229 | } 230 | -------------------------------------------------------------------------------- /x509/ber.go: -------------------------------------------------------------------------------- 1 | package x509 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | ) 7 | 8 | var encodeIndent = 0 9 | 10 | type asn1Object interface { 11 | EncodeTo(writer *bytes.Buffer) error 12 | } 13 | 14 | type asn1Structured struct { 15 | tagBytes []byte 16 | content []asn1Object 17 | } 18 | 19 | func (s asn1Structured) EncodeTo(out *bytes.Buffer) error { 20 | //fmt.Printf("%s--> tag: % X\n", strings.Repeat("| ", encodeIndent), s.tagBytes) 21 | encodeIndent++ 22 | inner := new(bytes.Buffer) 23 | for _, obj := range s.content { 24 | err := obj.EncodeTo(inner) 25 | if err != nil { 26 | return err 27 | } 28 | } 29 | encodeIndent-- 30 | out.Write(s.tagBytes) 31 | encodeLength(out, inner.Len()) 32 | out.Write(inner.Bytes()) 33 | return nil 34 | } 35 | 36 | type asn1Primitive struct { 37 | tagBytes []byte 38 | length int 39 | content []byte 40 | } 41 | 42 | func (p asn1Primitive) EncodeTo(out *bytes.Buffer) error { 43 | _, err := out.Write(p.tagBytes) 44 | if err != nil { 45 | return err 46 | } 47 | if err = encodeLength(out, p.length); err != nil { 48 | return err 49 | } 50 | //fmt.Printf("%s--> tag: % X length: %d\n", strings.Repeat("| ", encodeIndent), p.tagBytes, p.length) 51 | //fmt.Printf("%s--> content length: %d\n", strings.Repeat("| ", encodeIndent), len(p.content)) 52 | out.Write(p.content) 53 | 54 | return nil 55 | } 56 | 57 | func ber2der(ber []byte) ([]byte, error) { 58 | if len(ber) == 0 { 59 | return nil, errors.New("ber2der: input ber is empty") 60 | } 61 | //fmt.Printf("--> ber2der: Transcoding %d bytes\n", len(ber)) 62 | out := new(bytes.Buffer) 63 | 64 | obj, _, err := readObject(ber, 0) 65 | if err != nil { 66 | return nil, err 67 | } 68 | obj.EncodeTo(out) 69 | 70 | // if offset < len(ber) { 71 | // return nil, fmt.Errorf("ber2der: Content longer than expected. Got %d, expected %d", offset, len(ber)) 72 | //} 73 | 74 | return out.Bytes(), nil 75 | } 76 | 77 | // encodes lengths that are longer than 127 into string of bytes 78 | func marshalLongLength(out *bytes.Buffer, i int) (err error) { 79 | n := lengthLength(i) 80 | 81 | for ; n > 0; n-- { 82 | err = out.WriteByte(byte(i >> uint((n-1)*8))) 83 | if err != nil { 84 | return 85 | } 86 | } 87 | 88 | return nil 89 | } 90 | 91 | // computes the byte length of an encoded length value 92 | func lengthLength(i int) (numBytes int) { 93 | numBytes = 1 94 | for i > 255 { 95 | numBytes++ 96 | i >>= 8 97 | } 98 | return 99 | } 100 | 101 | // encodes the length in DER format 102 | // If the length fits in 7 bits, the value is encoded directly. 103 | // 104 | // Otherwise, the number of bytes to encode the length is first determined. 105 | // This number is likely to be 4 or less for a 32bit length. This number is 106 | // added to 0x80. The length is encoded in big endian encoding follow after 107 | // 108 | // Examples: 109 | // length | byte 1 | bytes n 110 | // 0 | 0x00 | - 111 | // 120 | 0x78 | - 112 | // 200 | 0x81 | 0xC8 113 | // 500 | 0x82 | 0x01 0xF4 114 | // 115 | func encodeLength(out *bytes.Buffer, length int) (err error) { 116 | if length >= 128 { 117 | l := lengthLength(length) 118 | err = out.WriteByte(0x80 | byte(l)) 119 | if err != nil { 120 | return 121 | } 122 | err = marshalLongLength(out, length) 123 | if err != nil { 124 | return 125 | } 126 | } else { 127 | err = out.WriteByte(byte(length)) 128 | if err != nil { 129 | return 130 | } 131 | } 132 | return 133 | } 134 | 135 | func readObject(ber []byte, offset int) (asn1Object, int, error) { 136 | //fmt.Printf("\n====> Starting readObject at offset: %d\n\n", offset) 137 | tagStart := offset 138 | b := ber[offset] 139 | offset++ 140 | tag := b & 0x1F // last 5 bits 141 | if tag == 0x1F { 142 | tag = 0 143 | for ber[offset] >= 0x80 { 144 | tag = tag*128 + ber[offset] - 0x80 145 | offset++ 146 | } 147 | tag = tag*128 + ber[offset] - 0x80 148 | offset++ 149 | } 150 | tagEnd := offset 151 | 152 | kind := b & 0x20 153 | /* 154 | if kind == 0 { 155 | fmt.Print("--> Primitive\n") 156 | } else { 157 | fmt.Print("--> Constructed\n") 158 | } 159 | */ 160 | // read length 161 | var length int 162 | l := ber[offset] 163 | offset++ 164 | indefinite := false 165 | if l > 0x80 { 166 | numberOfBytes := (int)(l & 0x7F) 167 | if numberOfBytes > 4 { // int is only guaranteed to be 32bit 168 | return nil, 0, errors.New("ber2der: BER tag length too long") 169 | } 170 | if numberOfBytes == 4 && (int)(ber[offset]) > 0x7F { 171 | return nil, 0, errors.New("ber2der: BER tag length is negative") 172 | } 173 | if 0x0 == (int)(ber[offset]) { 174 | return nil, 0, errors.New("ber2der: BER tag length has leading zero") 175 | } 176 | //fmt.Printf("--> (compute length) indicator byte: %x\n", l) 177 | //fmt.Printf("--> (compute length) length bytes: % X\n", ber[offset:offset+numberOfBytes]) 178 | for i := 0; i < numberOfBytes; i++ { 179 | length = length*256 + (int)(ber[offset]) 180 | offset++ 181 | } 182 | } else if l == 0x80 { 183 | indefinite = true 184 | } else { 185 | length = (int)(l) 186 | } 187 | 188 | //fmt.Printf("--> length : %d\n", length) 189 | contentEnd := offset + length 190 | if contentEnd > len(ber) { 191 | return nil, 0, errors.New("ber2der: BER tag length is more than available data") 192 | } 193 | //fmt.Printf("--> content start : %d\n", offset) 194 | //fmt.Printf("--> content end : %d\n", contentEnd) 195 | //fmt.Printf("--> content : % X\n", ber[offset:contentEnd]) 196 | var obj asn1Object 197 | if indefinite && kind == 0 { 198 | return nil, 0, errors.New("ber2der: Indefinite form tag must have constructed encoding") 199 | } 200 | if kind == 0 { 201 | obj = asn1Primitive{ 202 | tagBytes: ber[tagStart:tagEnd], 203 | length: length, 204 | content: ber[offset:contentEnd], 205 | } 206 | } else { 207 | var subObjects []asn1Object 208 | for (offset < contentEnd) || indefinite { 209 | var subObj asn1Object 210 | var err error 211 | subObj, offset, err = readObject(ber, offset) 212 | if err != nil { 213 | return nil, 0, err 214 | } 215 | subObjects = append(subObjects, subObj) 216 | 217 | if indefinite { 218 | terminated, err := isIndefiniteTermination(ber, offset) 219 | if err != nil { 220 | return nil, 0, err 221 | } 222 | 223 | if terminated { 224 | break 225 | } 226 | } 227 | } 228 | obj = asn1Structured{ 229 | tagBytes: ber[tagStart:tagEnd], 230 | content: subObjects, 231 | } 232 | } 233 | 234 | // Apply indefinite form length with 0x0000 terminator. 235 | if indefinite { 236 | contentEnd = offset + 2 237 | } 238 | 239 | return obj, contentEnd, nil 240 | } 241 | 242 | func isIndefiniteTermination(ber []byte, offset int) (bool, error) { 243 | if len(ber)-offset < 2 { 244 | return false, errors.New("ber2der: Invalid BER format") 245 | } 246 | 247 | return bytes.Index(ber[offset:], []byte{0x0, 0x0}) == 0, nil 248 | } 249 | -------------------------------------------------------------------------------- /gmtls/gmcredentials/credentials.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Suzhou Tongji Fintech Research Institute 2017 All Rights Reserved. 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | package gmcredentials 17 | 18 | import ( 19 | "errors" 20 | "fmt" 21 | "io/ioutil" 22 | "net" 23 | "strings" 24 | 25 | "github.com/tjfoc/gmsm/gmtls" 26 | "github.com/tjfoc/gmsm/x509" 27 | "golang.org/x/net/context" 28 | "google.golang.org/grpc/credentials" 29 | ) 30 | 31 | var ( 32 | // alpnProtoStr are the specified application level protocols for gRPC. 33 | alpnProtoStr = []string{"h2"} 34 | ) 35 | 36 | // PerRPCCredentials defines the common interface for the credentials which need to 37 | // attach security information to every RPC (e.g., oauth2). 38 | type PerRPCCredentials interface { 39 | // GetRequestMetadata gets the current request metadata, refreshing 40 | // tokens if required. This should be called by the transport layer on 41 | // each request, and the data should be populated in headers or other 42 | // context. uri is the URI of the entry point for the request. When 43 | // supported by the underlying implementation, ctx can be used for 44 | // timeout and cancellation. 45 | // TODO(zhaoq): Define the set of the qualified keys instead of leaving 46 | // it as an arbitrary string. 47 | GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) 48 | // RequireTransportSecurity indicates whether the credentials requires 49 | // transport security. 50 | RequireTransportSecurity() bool 51 | } 52 | 53 | // ProtocolInfo provides information regarding the gRPC wire protocol version, 54 | // security protocol, security protocol version in use, server name, etc. 55 | type ProtocolInfo struct { 56 | // ProtocolVersion is the gRPC wire protocol version. 57 | ProtocolVersion string 58 | // SecurityProtocol is the security protocol in use. 59 | SecurityProtocol string 60 | // SecurityVersion is the security protocol version. 61 | SecurityVersion string 62 | // ServerName is the user-configured server name. 63 | ServerName string 64 | } 65 | 66 | // AuthInfo defines the common interface for the auth information the users are interested in. 67 | type AuthInfo interface { 68 | AuthType() string 69 | } 70 | 71 | var ( 72 | // ErrConnDispatched indicates that rawConn has been dispatched out of gRPC 73 | // and the caller should not close rawConn. 74 | ErrConnDispatched = errors.New("credentials: rawConn is dispatched out of gRPC") 75 | ) 76 | 77 | // TLSInfo contains the auth information for a TLS authenticated connection. 78 | // It implements the AuthInfo interface. 79 | type TLSInfo struct { 80 | State gmtls.ConnectionState 81 | } 82 | 83 | // AuthType returns the type of TLSInfo as a string. 84 | func (t TLSInfo) AuthType() string { 85 | return "tls" 86 | } 87 | 88 | // tlsCreds is the credentials required for authenticating a connection using TLS. 89 | type tlsCreds struct { 90 | // TLS configuration 91 | config *gmtls.Config 92 | } 93 | 94 | func (c tlsCreds) Info() credentials.ProtocolInfo { 95 | return credentials.ProtocolInfo{ 96 | SecurityProtocol: "tls", 97 | SecurityVersion: "1.2", 98 | ServerName: c.config.ServerName, 99 | } 100 | } 101 | 102 | func (c *tlsCreds) ClientHandshake(ctx context.Context, addr string, rawConn net.Conn) (_ net.Conn, _ credentials.AuthInfo, err error) { 103 | // use local cfg to avoid clobbering ServerName if using multiple endpoints 104 | cfg := cloneTLSConfig(c.config) 105 | if cfg.ServerName == "" { 106 | colonPos := strings.LastIndex(addr, ":") 107 | if colonPos == -1 { 108 | colonPos = len(addr) 109 | } 110 | cfg.ServerName = addr[:colonPos] 111 | } 112 | conn := gmtls.Client(rawConn, cfg) 113 | errChannel := make(chan error, 1) 114 | go func() { 115 | errChannel <- conn.Handshake() 116 | }() 117 | select { 118 | case err := <-errChannel: 119 | if err != nil { 120 | return nil, nil, err 121 | } 122 | case <-ctx.Done(): 123 | return nil, nil, ctx.Err() 124 | } 125 | return conn, TLSInfo{conn.ConnectionState()}, nil 126 | } 127 | 128 | func (c *tlsCreds) ServerHandshake(rawConn net.Conn) (net.Conn, credentials.AuthInfo, error) { 129 | conn := gmtls.Server(rawConn, c.config) 130 | if err := conn.Handshake(); err != nil { 131 | return nil, nil, err 132 | } 133 | return conn, TLSInfo{conn.ConnectionState()}, nil 134 | } 135 | 136 | func (c *tlsCreds) Clone() credentials.TransportCredentials { 137 | return NewTLS(c.config) 138 | } 139 | 140 | func (c *tlsCreds) OverrideServerName(serverNameOverride string) error { 141 | c.config.ServerName = serverNameOverride 142 | return nil 143 | } 144 | 145 | // NewTLS uses c to construct a TransportCredentials based on TLS. 146 | func NewTLS(c *gmtls.Config) credentials.TransportCredentials { 147 | tc := &tlsCreds{cloneTLSConfig(c)} 148 | tc.config.NextProtos = alpnProtoStr 149 | return tc 150 | } 151 | 152 | // NewClientTLSFromCert constructs TLS credentials from the input certificate for client. 153 | // serverNameOverride is for testing only. If set to a non empty string, 154 | // it will override the virtual host name of authority (e.g. :authority header field) in requests. 155 | func NewClientTLSFromCert(cp *x509.CertPool, serverNameOverride string) credentials.TransportCredentials { 156 | return NewTLS(&gmtls.Config{GMSupport: &gmtls.GMSupport{}, ServerName: serverNameOverride, RootCAs: cp}) 157 | } 158 | 159 | // NewClientTLSFromFile constructs TLS credentials from the input certificate file for client. 160 | // serverNameOverride is for testing only. If set to a non empty string, 161 | // it will override the virtual host name of authority (e.g. :authority header field) in requests. 162 | func NewClientTLSFromFile(certFile, serverNameOverride string) (credentials.TransportCredentials, error) { 163 | b, err := ioutil.ReadFile(certFile) 164 | if err != nil { 165 | return nil, err 166 | } 167 | cp := x509.NewCertPool() 168 | if !cp.AppendCertsFromPEM(b) { 169 | return nil, fmt.Errorf("credentials: failed to append certificates") 170 | } 171 | return NewTLS(&gmtls.Config{ServerName: serverNameOverride, RootCAs: cp}), nil 172 | } 173 | 174 | // NewServerTLSFromCert constructs TLS credentials from the input certificate for server. 175 | func NewServerTLSFromCert(cert *gmtls.Certificate) credentials.TransportCredentials { 176 | return NewTLS(&gmtls.Config{Certificates: []gmtls.Certificate{*cert}}) 177 | } 178 | 179 | // NewServerTLSFromFile constructs TLS credentials from the input certificate file and key 180 | // file for server. 181 | func NewServerTLSFromFile(certFile, keyFile string) (credentials.TransportCredentials, error) { 182 | cert, err := gmtls.LoadX509KeyPair(certFile, keyFile) 183 | if err != nil { 184 | return nil, err 185 | } 186 | return NewTLS(&gmtls.Config{Certificates: []gmtls.Certificate{cert}}), nil 187 | } 188 | -------------------------------------------------------------------------------- /pkcs12/rc2.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package rc2 implements the RC2 cipher 6 | /* 7 | https://www.ietf.org/rfc/rfc2268.txt 8 | http://people.csail.mit.edu/rivest/pubs/KRRR98.pdf 9 | 10 | This code is licensed under the MIT license. 11 | */ 12 | package pkcs12 13 | 14 | import ( 15 | "crypto/cipher" 16 | "encoding/binary" 17 | ) 18 | 19 | // The rc2 block size in bytes 20 | const BlockSize = 8 21 | 22 | type rc2Cipher struct { 23 | k [64]uint16 24 | } 25 | 26 | // New returns a new rc2 cipher with the given key and effective key length t1 27 | func New(key []byte, t1 int) (cipher.Block, error) { 28 | // TODO(dgryski): error checking for key length 29 | return &rc2Cipher{ 30 | k: expandKey(key, t1), 31 | }, nil 32 | } 33 | 34 | func (*rc2Cipher) BlockSize() int { return BlockSize } 35 | 36 | var piTable = [256]byte{ 37 | 0xd9, 0x78, 0xf9, 0xc4, 0x19, 0xdd, 0xb5, 0xed, 0x28, 0xe9, 0xfd, 0x79, 0x4a, 0xa0, 0xd8, 0x9d, 38 | 0xc6, 0x7e, 0x37, 0x83, 0x2b, 0x76, 0x53, 0x8e, 0x62, 0x4c, 0x64, 0x88, 0x44, 0x8b, 0xfb, 0xa2, 39 | 0x17, 0x9a, 0x59, 0xf5, 0x87, 0xb3, 0x4f, 0x13, 0x61, 0x45, 0x6d, 0x8d, 0x09, 0x81, 0x7d, 0x32, 40 | 0xbd, 0x8f, 0x40, 0xeb, 0x86, 0xb7, 0x7b, 0x0b, 0xf0, 0x95, 0x21, 0x22, 0x5c, 0x6b, 0x4e, 0x82, 41 | 0x54, 0xd6, 0x65, 0x93, 0xce, 0x60, 0xb2, 0x1c, 0x73, 0x56, 0xc0, 0x14, 0xa7, 0x8c, 0xf1, 0xdc, 42 | 0x12, 0x75, 0xca, 0x1f, 0x3b, 0xbe, 0xe4, 0xd1, 0x42, 0x3d, 0xd4, 0x30, 0xa3, 0x3c, 0xb6, 0x26, 43 | 0x6f, 0xbf, 0x0e, 0xda, 0x46, 0x69, 0x07, 0x57, 0x27, 0xf2, 0x1d, 0x9b, 0xbc, 0x94, 0x43, 0x03, 44 | 0xf8, 0x11, 0xc7, 0xf6, 0x90, 0xef, 0x3e, 0xe7, 0x06, 0xc3, 0xd5, 0x2f, 0xc8, 0x66, 0x1e, 0xd7, 45 | 0x08, 0xe8, 0xea, 0xde, 0x80, 0x52, 0xee, 0xf7, 0x84, 0xaa, 0x72, 0xac, 0x35, 0x4d, 0x6a, 0x2a, 46 | 0x96, 0x1a, 0xd2, 0x71, 0x5a, 0x15, 0x49, 0x74, 0x4b, 0x9f, 0xd0, 0x5e, 0x04, 0x18, 0xa4, 0xec, 47 | 0xc2, 0xe0, 0x41, 0x6e, 0x0f, 0x51, 0xcb, 0xcc, 0x24, 0x91, 0xaf, 0x50, 0xa1, 0xf4, 0x70, 0x39, 48 | 0x99, 0x7c, 0x3a, 0x85, 0x23, 0xb8, 0xb4, 0x7a, 0xfc, 0x02, 0x36, 0x5b, 0x25, 0x55, 0x97, 0x31, 49 | 0x2d, 0x5d, 0xfa, 0x98, 0xe3, 0x8a, 0x92, 0xae, 0x05, 0xdf, 0x29, 0x10, 0x67, 0x6c, 0xba, 0xc9, 50 | 0xd3, 0x00, 0xe6, 0xcf, 0xe1, 0x9e, 0xa8, 0x2c, 0x63, 0x16, 0x01, 0x3f, 0x58, 0xe2, 0x89, 0xa9, 51 | 0x0d, 0x38, 0x34, 0x1b, 0xab, 0x33, 0xff, 0xb0, 0xbb, 0x48, 0x0c, 0x5f, 0xb9, 0xb1, 0xcd, 0x2e, 52 | 0xc5, 0xf3, 0xdb, 0x47, 0xe5, 0xa5, 0x9c, 0x77, 0x0a, 0xa6, 0x20, 0x68, 0xfe, 0x7f, 0xc1, 0xad, 53 | } 54 | 55 | func expandKey(key []byte, t1 int) [64]uint16 { 56 | 57 | l := make([]byte, 128) 58 | copy(l, key) 59 | 60 | var t = len(key) 61 | var t8 = (t1 + 7) / 8 62 | var tm = byte(255 % uint(1<<(8+uint(t1)-8*uint(t8)))) 63 | 64 | for i := len(key); i < 128; i++ { 65 | l[i] = piTable[l[i-1]+l[uint8(i-t)]] 66 | } 67 | 68 | l[128-t8] = piTable[l[128-t8]&tm] 69 | 70 | for i := 127 - t8; i >= 0; i-- { 71 | l[i] = piTable[l[i+1]^l[i+t8]] 72 | } 73 | 74 | var k [64]uint16 75 | 76 | for i := range k { 77 | k[i] = uint16(l[2*i]) + uint16(l[2*i+1])*256 78 | } 79 | 80 | return k 81 | } 82 | 83 | func rotl16(x uint16, b uint) uint16 { 84 | return (x >> (16 - b)) | (x << b) 85 | } 86 | 87 | func (c *rc2Cipher) Encrypt(dst, src []byte) { 88 | 89 | r0 := binary.LittleEndian.Uint16(src[0:]) 90 | r1 := binary.LittleEndian.Uint16(src[2:]) 91 | r2 := binary.LittleEndian.Uint16(src[4:]) 92 | r3 := binary.LittleEndian.Uint16(src[6:]) 93 | 94 | var j int 95 | 96 | for j <= 16 { 97 | // mix r0 98 | r0 = r0 + c.k[j] + (r3 & r2) + ((^r3) & r1) 99 | r0 = rotl16(r0, 1) 100 | j++ 101 | 102 | // mix r1 103 | r1 = r1 + c.k[j] + (r0 & r3) + ((^r0) & r2) 104 | r1 = rotl16(r1, 2) 105 | j++ 106 | 107 | // mix r2 108 | r2 = r2 + c.k[j] + (r1 & r0) + ((^r1) & r3) 109 | r2 = rotl16(r2, 3) 110 | j++ 111 | 112 | // mix r3 113 | r3 = r3 + c.k[j] + (r2 & r1) + ((^r2) & r0) 114 | r3 = rotl16(r3, 5) 115 | j++ 116 | 117 | } 118 | 119 | r0 = r0 + c.k[r3&63] 120 | r1 = r1 + c.k[r0&63] 121 | r2 = r2 + c.k[r1&63] 122 | r3 = r3 + c.k[r2&63] 123 | 124 | for j <= 40 { 125 | 126 | // mix r0 127 | r0 = r0 + c.k[j] + (r3 & r2) + ((^r3) & r1) 128 | r0 = rotl16(r0, 1) 129 | j++ 130 | 131 | // mix r1 132 | r1 = r1 + c.k[j] + (r0 & r3) + ((^r0) & r2) 133 | r1 = rotl16(r1, 2) 134 | j++ 135 | 136 | // mix r2 137 | r2 = r2 + c.k[j] + (r1 & r0) + ((^r1) & r3) 138 | r2 = rotl16(r2, 3) 139 | j++ 140 | 141 | // mix r3 142 | r3 = r3 + c.k[j] + (r2 & r1) + ((^r2) & r0) 143 | r3 = rotl16(r3, 5) 144 | j++ 145 | 146 | } 147 | 148 | r0 = r0 + c.k[r3&63] 149 | r1 = r1 + c.k[r0&63] 150 | r2 = r2 + c.k[r1&63] 151 | r3 = r3 + c.k[r2&63] 152 | 153 | for j <= 60 { 154 | 155 | // mix r0 156 | r0 = r0 + c.k[j] + (r3 & r2) + ((^r3) & r1) 157 | r0 = rotl16(r0, 1) 158 | j++ 159 | 160 | // mix r1 161 | r1 = r1 + c.k[j] + (r0 & r3) + ((^r0) & r2) 162 | r1 = rotl16(r1, 2) 163 | j++ 164 | 165 | // mix r2 166 | r2 = r2 + c.k[j] + (r1 & r0) + ((^r1) & r3) 167 | r2 = rotl16(r2, 3) 168 | j++ 169 | 170 | // mix r3 171 | r3 = r3 + c.k[j] + (r2 & r1) + ((^r2) & r0) 172 | r3 = rotl16(r3, 5) 173 | j++ 174 | } 175 | 176 | binary.LittleEndian.PutUint16(dst[0:], r0) 177 | binary.LittleEndian.PutUint16(dst[2:], r1) 178 | binary.LittleEndian.PutUint16(dst[4:], r2) 179 | binary.LittleEndian.PutUint16(dst[6:], r3) 180 | } 181 | 182 | func (c *rc2Cipher) Decrypt(dst, src []byte) { 183 | 184 | r0 := binary.LittleEndian.Uint16(src[0:]) 185 | r1 := binary.LittleEndian.Uint16(src[2:]) 186 | r2 := binary.LittleEndian.Uint16(src[4:]) 187 | r3 := binary.LittleEndian.Uint16(src[6:]) 188 | 189 | j := 63 190 | 191 | for j >= 44 { 192 | // unmix r3 193 | r3 = rotl16(r3, 16-5) 194 | r3 = r3 - c.k[j] - (r2 & r1) - ((^r2) & r0) 195 | j-- 196 | 197 | // unmix r2 198 | r2 = rotl16(r2, 16-3) 199 | r2 = r2 - c.k[j] - (r1 & r0) - ((^r1) & r3) 200 | j-- 201 | 202 | // unmix r1 203 | r1 = rotl16(r1, 16-2) 204 | r1 = r1 - c.k[j] - (r0 & r3) - ((^r0) & r2) 205 | j-- 206 | 207 | // unmix r0 208 | r0 = rotl16(r0, 16-1) 209 | r0 = r0 - c.k[j] - (r3 & r2) - ((^r3) & r1) 210 | j-- 211 | } 212 | 213 | r3 = r3 - c.k[r2&63] 214 | r2 = r2 - c.k[r1&63] 215 | r1 = r1 - c.k[r0&63] 216 | r0 = r0 - c.k[r3&63] 217 | 218 | for j >= 20 { 219 | // unmix r3 220 | r3 = rotl16(r3, 16-5) 221 | r3 = r3 - c.k[j] - (r2 & r1) - ((^r2) & r0) 222 | j-- 223 | 224 | // unmix r2 225 | r2 = rotl16(r2, 16-3) 226 | r2 = r2 - c.k[j] - (r1 & r0) - ((^r1) & r3) 227 | j-- 228 | 229 | // unmix r1 230 | r1 = rotl16(r1, 16-2) 231 | r1 = r1 - c.k[j] - (r0 & r3) - ((^r0) & r2) 232 | j-- 233 | 234 | // unmix r0 235 | r0 = rotl16(r0, 16-1) 236 | r0 = r0 - c.k[j] - (r3 & r2) - ((^r3) & r1) 237 | j-- 238 | 239 | } 240 | 241 | r3 = r3 - c.k[r2&63] 242 | r2 = r2 - c.k[r1&63] 243 | r1 = r1 - c.k[r0&63] 244 | r0 = r0 - c.k[r3&63] 245 | 246 | for j >= 0 { 247 | 248 | // unmix r3 249 | r3 = rotl16(r3, 16-5) 250 | r3 = r3 - c.k[j] - (r2 & r1) - ((^r2) & r0) 251 | j-- 252 | 253 | // unmix r2 254 | r2 = rotl16(r2, 16-3) 255 | r2 = r2 - c.k[j] - (r1 & r0) - ((^r1) & r3) 256 | j-- 257 | 258 | // unmix r1 259 | r1 = rotl16(r1, 16-2) 260 | r1 = r1 - c.k[j] - (r0 & r3) - ((^r0) & r2) 261 | j-- 262 | 263 | // unmix r0 264 | r0 = rotl16(r0, 16-1) 265 | r0 = r0 - c.k[j] - (r3 & r2) - ((^r3) & r1) 266 | j-- 267 | 268 | } 269 | 270 | binary.LittleEndian.PutUint16(dst[0:], r0) 271 | binary.LittleEndian.PutUint16(dst[2:], r1) 272 | binary.LittleEndian.PutUint16(dst[4:], r2) 273 | binary.LittleEndian.PutUint16(dst[6:], r3) 274 | } 275 | -------------------------------------------------------------------------------- /pkcs12/pkcs8.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package pkcs12 6 | 7 | import ( 8 | "crypto/ecdsa" 9 | "crypto/elliptic" 10 | "crypto/rsa" 11 | "crypto/x509" 12 | "crypto/x509/pkix" 13 | "encoding/asn1" 14 | "errors" 15 | "github.com/tjfoc/gmsm/sm2" 16 | "fmt" 17 | "math/big" 18 | ) 19 | 20 | type pkcs8 struct { // Duplicated from x509 package 21 | Version int 22 | Algo pkix.AlgorithmIdentifier 23 | PrivateKey []byte 24 | } 25 | 26 | var ( // Duplicated from x509 package 27 | oidPublicKeyRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1} 28 | oidPublicKeyECDSA = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1} 29 | ) 30 | 31 | var ( // Duplicated from x509 package 32 | oidNamedCurveP224 = asn1.ObjectIdentifier{1, 3, 132, 0, 33} 33 | oidNamedCurveP256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 3, 1, 7} 34 | oidNamedCurveP384 = asn1.ObjectIdentifier{1, 3, 132, 0, 34} 35 | oidNamedCurveP521 = asn1.ObjectIdentifier{1, 3, 132, 0, 35} 36 | oidNamedCurveP256SM2 = asn1.ObjectIdentifier{1, 2, 156, 10197, 1, 301} // I get the SM2 ID through parsing the pem file generated by gmssl 37 | ) 38 | 39 | func oidFromNamedCurve(curve elliptic.Curve) (asn1.ObjectIdentifier, bool) { // Duplicated from x509 package 40 | switch curve { 41 | case elliptic.P224(): 42 | return oidNamedCurveP224, true 43 | case elliptic.P256(): 44 | return oidNamedCurveP256, true 45 | case elliptic.P384(): 46 | return oidNamedCurveP384, true 47 | case elliptic.P521(): 48 | return oidNamedCurveP521, true 49 | case sm2.P256Sm2(): 50 | return oidNamedCurveP256SM2, true 51 | } 52 | 53 | return nil, false 54 | } 55 | func namedCurveFromOID(oid asn1.ObjectIdentifier) elliptic.Curve { 56 | switch { 57 | case oid.Equal(oidNamedCurveP224): 58 | return elliptic.P224() 59 | case oid.Equal(oidNamedCurveP256): 60 | return elliptic.P256() 61 | case oid.Equal(oidNamedCurveP384): 62 | return elliptic.P384() 63 | case oid.Equal(oidNamedCurveP521): 64 | return elliptic.P521() 65 | case oid.Equal(oidNamedCurveP256SM2): 66 | return sm2.P256Sm2() 67 | } 68 | return nil 69 | } 70 | func ParsePKCS8PrivateKey(der []byte) (key interface{}, err error) { 71 | var privKey pkcs8 72 | if _, err := asn1.Unmarshal(der, &privKey); err != nil { 73 | return nil, err 74 | } 75 | switch { 76 | case privKey.Algo.Algorithm.Equal(oidPublicKeyECDSA): 77 | bytes := privKey.Algo.Parameters.FullBytes 78 | namedCurveOID := new(asn1.ObjectIdentifier) 79 | if _, err := asn1.Unmarshal(bytes, namedCurveOID); err != nil { 80 | namedCurveOID = nil 81 | } 82 | key, err = parseECPrivateKey(namedCurveOID, privKey.PrivateKey) 83 | if err != nil { 84 | return nil, errors.New("x509: failed to parse EC private key embedded in PKCS#8: " + err.Error()) 85 | } 86 | return key, nil 87 | 88 | default: 89 | return nil, fmt.Errorf("x509: PKCS#8 wrapping contained private key with unknown algorithm: %v", privKey.Algo.Algorithm) 90 | } 91 | } 92 | func parseECPrivateKey(namedCurveOID *asn1.ObjectIdentifier, der []byte) (key *ecdsa.PrivateKey, err error) { 93 | var privKey ecPrivateKey 94 | if _, err := asn1.Unmarshal(der, &privKey); err != nil { 95 | return nil, errors.New("x509: failed to parse EC private key: " + err.Error()) 96 | } 97 | if privKey.Version != 1 { 98 | return nil, fmt.Errorf("x509: unknown EC private key version %d", privKey.Version) 99 | } 100 | 101 | var curve elliptic.Curve 102 | if namedCurveOID != nil { 103 | curve = namedCurveFromOID(*namedCurveOID) 104 | } else { 105 | curve = namedCurveFromOID(privKey.NamedCurveOID) 106 | } 107 | if curve == nil { 108 | return nil, errors.New("x509: unknown elliptic curve") 109 | } 110 | 111 | k := new(big.Int).SetBytes(privKey.PrivateKey) 112 | curveOrder := curve.Params().N 113 | if k.Cmp(curveOrder) >= 0 { 114 | return nil, errors.New("x509: invalid elliptic curve private key value") 115 | } 116 | priv := new(ecdsa.PrivateKey) 117 | priv.Curve = curve 118 | priv.D = k 119 | 120 | privateKey := make([]byte, (curveOrder.BitLen()+7)/8) 121 | 122 | // Some private keys have leading zero padding. This is invalid 123 | // according to [SEC1], but this code will ignore it. 124 | for len(privKey.PrivateKey) > len(privateKey) { 125 | if privKey.PrivateKey[0] != 0 { 126 | return nil, errors.New("x509: invalid private key length") 127 | } 128 | privKey.PrivateKey = privKey.PrivateKey[1:] 129 | } 130 | 131 | // Some private keys remove all leading zeros, this is also invalid 132 | // according to [SEC1] but since OpenSSL used to do this, we ignore 133 | // this too. 134 | copy(privateKey[len(privateKey)-len(privKey.PrivateKey):], privKey.PrivateKey) 135 | priv.X, priv.Y = curve.ScalarBaseMult(privateKey) 136 | 137 | return priv, nil 138 | } 139 | func marshalPKCS8PrivateKey(key interface{}) (der []byte, err error) { 140 | var privKey pkcs8 141 | switch key := key.(type) { 142 | case *rsa.PrivateKey: 143 | privKey.Algo.Algorithm = oidPublicKeyRSA 144 | // This is a NULL parameters value which is technically 145 | // superfluous, but most other code includes it. 146 | privKey.Algo.Parameters = asn1.RawValue{ 147 | Tag: 5, 148 | } 149 | privKey.PrivateKey = x509.MarshalPKCS1PrivateKey(key) 150 | case *ecdsa.PrivateKey: 151 | privKey.Algo.Algorithm = oidPublicKeyECDSA 152 | namedCurveOID, ok := oidFromNamedCurve(key.Curve) 153 | if !ok { 154 | return nil, errors.New("go-pkcs12: unknown elliptic curve") 155 | } 156 | if privKey.Algo.Parameters.FullBytes, err = asn1.Marshal(namedCurveOID); err != nil { 157 | return nil, errors.New("go-pkcs12: failed to embed OID of named curve in PKCS#8: " + err.Error()) 158 | } 159 | if privKey.PrivateKey, err =x509.MarshalECPrivateKey(key); err != nil { 160 | return nil, errors.New("go-pkcs12: failed to embed EC private key in PKCS#8: " + err.Error()) 161 | } 162 | case *sm2.PrivateKey: 163 | privKey.Algo.Algorithm = oidPublicKeyECDSA 164 | namedCurveOID, ok := oidFromNamedCurve(key.Curve) 165 | if !ok { 166 | return nil, errors.New("go-pkcs12: unknown elliptic curve") 167 | } 168 | if privKey.Algo.Parameters.FullBytes, err = asn1.Marshal(namedCurveOID); err != nil { 169 | return nil, errors.New("go-pkcs12: failed to embed OID of named curve in PKCS#8: " + err.Error()) 170 | } 171 | if privKey.PrivateKey, err = MarshalECPrivateKey(key); err != nil { 172 | return nil, errors.New("go-pkcs12: failed to embed EC private key in PKCS#8: " + err.Error()) 173 | } 174 | default: 175 | return nil, errors.New("go-pkcs12: only RSA and ECDSA private keys supported") 176 | } 177 | return asn1.Marshal(privKey) 178 | } 179 | func MarshalECPrivateKey(key *sm2.PrivateKey) ([]byte, error) { 180 | oid, ok := oidFromNamedCurve(key.Curve) 181 | if !ok { 182 | return nil, errors.New("x509: unknown elliptic curve") 183 | } 184 | 185 | return MarshalPrivateKey(key, oid) 186 | } 187 | func MarshalPrivateKey(key *sm2.PrivateKey, oid asn1.ObjectIdentifier)([]byte,error){ 188 | privateKeyBytes := key.D.Bytes() 189 | paddedPrivateKey := make([]byte, (key.Curve.Params().N.BitLen()+7)/8) 190 | copy(paddedPrivateKey[len(paddedPrivateKey)-len(privateKeyBytes):], privateKeyBytes) 191 | return asn1.Marshal(ecPrivateKey{ 192 | Version: 1, 193 | PrivateKey: paddedPrivateKey, 194 | NamedCurveOID: oid, 195 | PublicKey: asn1.BitString{Bytes: elliptic.Marshal(key.Curve, key.X, key.Y)}, 196 | }) 197 | } 198 | type ecPrivateKey struct { 199 | Version int 200 | PrivateKey []byte 201 | NamedCurveOID asn1.ObjectIdentifier `asn1:"optional,explicit,tag:0"` 202 | PublicKey asn1.BitString `asn1:"optional,explicit,tag:1"` 203 | } -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 3 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 4 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 5 | github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= 6 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 7 | github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= 8 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 9 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 10 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 11 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 12 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 13 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 14 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 15 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 16 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 17 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 18 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 19 | github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= 20 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 21 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 22 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 23 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 24 | github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= 25 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 26 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 27 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 28 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 29 | golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee h1:4yd7jl+vXjalO5ztz6Vc1VADv+S/80LGJmyl1ROJ2AI= 30 | golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 31 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 32 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 33 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 34 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 35 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 36 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 37 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 38 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 39 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 40 | golang.org/x/net v0.0.0-20201010224723-4f7140c49acb h1:mUVeFHoDKis5nxCAzoAi7E8Ghb86EXh/RK6wtvJIqRY= 41 | golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 42 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 43 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 44 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 45 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 46 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 47 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 48 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 49 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA= 50 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 51 | golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= 52 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 53 | golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= 54 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 55 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 56 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 57 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 58 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 59 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 60 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= 61 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 62 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 63 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 64 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 65 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE= 66 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 67 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 68 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 69 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= 70 | google.golang.org/grpc v1.31.0 h1:T7P4R73V3SSDPhH7WW7ATbfViLtmamH0DKrP3f9AuDI= 71 | google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 72 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 73 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 74 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 75 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 76 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 77 | google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= 78 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 79 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 80 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 81 | -------------------------------------------------------------------------------- /sm3/sm3.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Suzhou Tongji Fintech Research Institute 2017 All Rights Reserved. 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | package sm3 17 | 18 | import ( 19 | "encoding/binary" 20 | "hash" 21 | ) 22 | 23 | type SM3 struct { 24 | digest [8]uint32 // digest represents the partial evaluation of V 25 | length uint64 // length of the message 26 | unhandleMsg []byte // uint8 // 27 | } 28 | 29 | func (sm3 *SM3) ff0(x, y, z uint32) uint32 { return x ^ y ^ z } 30 | 31 | func (sm3 *SM3) ff1(x, y, z uint32) uint32 { return (x & y) | (x & z) | (y & z) } 32 | 33 | func (sm3 *SM3) gg0(x, y, z uint32) uint32 { return x ^ y ^ z } 34 | 35 | func (sm3 *SM3) gg1(x, y, z uint32) uint32 { return (x & y) | (^x & z) } 36 | 37 | func (sm3 *SM3) p0(x uint32) uint32 { return x ^ sm3.leftRotate(x, 9) ^ sm3.leftRotate(x, 17) } 38 | 39 | func (sm3 *SM3) p1(x uint32) uint32 { return x ^ sm3.leftRotate(x, 15) ^ sm3.leftRotate(x, 23) } 40 | 41 | func (sm3 *SM3) leftRotate(x uint32, i uint32) uint32 { return x<<(i%32) | x>>(32-i%32) } 42 | 43 | func (sm3 *SM3) pad() []byte { 44 | msg := sm3.unhandleMsg 45 | msg = append(msg, 0x80) // Append '1' 46 | blockSize := 64 // Append until the resulting message length (in bits) is congruent to 448 (mod 512) 47 | for len(msg)%blockSize != 56 { 48 | msg = append(msg, 0x00) 49 | } 50 | // append message length 51 | msg = append(msg, uint8(sm3.length>>56&0xff)) 52 | msg = append(msg, uint8(sm3.length>>48&0xff)) 53 | msg = append(msg, uint8(sm3.length>>40&0xff)) 54 | msg = append(msg, uint8(sm3.length>>32&0xff)) 55 | msg = append(msg, uint8(sm3.length>>24&0xff)) 56 | msg = append(msg, uint8(sm3.length>>16&0xff)) 57 | msg = append(msg, uint8(sm3.length>>8&0xff)) 58 | msg = append(msg, uint8(sm3.length>>0&0xff)) 59 | 60 | if len(msg)%64 != 0 { 61 | panic("------SM3 Pad: error msgLen =") 62 | } 63 | return msg 64 | } 65 | 66 | func (sm3 *SM3) update(msg []byte) { 67 | var w [68]uint32 68 | var w1 [64]uint32 69 | 70 | a, b, c, d, e, f, g, h := sm3.digest[0], sm3.digest[1], sm3.digest[2], sm3.digest[3], sm3.digest[4], sm3.digest[5], sm3.digest[6], sm3.digest[7] 71 | for len(msg) >= 64 { 72 | for i := 0; i < 16; i++ { 73 | w[i] = binary.BigEndian.Uint32(msg[4*i : 4*(i+1)]) 74 | } 75 | for i := 16; i < 68; i++ { 76 | w[i] = sm3.p1(w[i-16]^w[i-9]^sm3.leftRotate(w[i-3], 15)) ^ sm3.leftRotate(w[i-13], 7) ^ w[i-6] 77 | } 78 | for i := 0; i < 64; i++ { 79 | w1[i] = w[i] ^ w[i+4] 80 | } 81 | A, B, C, D, E, F, G, H := a, b, c, d, e, f, g, h 82 | for i := 0; i < 16; i++ { 83 | SS1 := sm3.leftRotate(sm3.leftRotate(A, 12)+E+sm3.leftRotate(0x79cc4519, uint32(i)), 7) 84 | SS2 := SS1 ^ sm3.leftRotate(A, 12) 85 | TT1 := sm3.ff0(A, B, C) + D + SS2 + w1[i] 86 | TT2 := sm3.gg0(E, F, G) + H + SS1 + w[i] 87 | D = C 88 | C = sm3.leftRotate(B, 9) 89 | B = A 90 | A = TT1 91 | H = G 92 | G = sm3.leftRotate(F, 19) 93 | F = E 94 | E = sm3.p0(TT2) 95 | } 96 | for i := 16; i < 64; i++ { 97 | SS1 := sm3.leftRotate(sm3.leftRotate(A, 12)+E+sm3.leftRotate(0x7a879d8a, uint32(i)), 7) 98 | SS2 := SS1 ^ sm3.leftRotate(A, 12) 99 | TT1 := sm3.ff1(A, B, C) + D + SS2 + w1[i] 100 | TT2 := sm3.gg1(E, F, G) + H + SS1 + w[i] 101 | D = C 102 | C = sm3.leftRotate(B, 9) 103 | B = A 104 | A = TT1 105 | H = G 106 | G = sm3.leftRotate(F, 19) 107 | F = E 108 | E = sm3.p0(TT2) 109 | } 110 | a ^= A 111 | b ^= B 112 | c ^= C 113 | d ^= D 114 | e ^= E 115 | f ^= F 116 | g ^= G 117 | h ^= H 118 | msg = msg[64:] 119 | } 120 | sm3.digest[0], sm3.digest[1], sm3.digest[2], sm3.digest[3], sm3.digest[4], sm3.digest[5], sm3.digest[6], sm3.digest[7] = a, b, c, d, e, f, g, h 121 | } 122 | func (sm3 *SM3) update2(msg []byte,) [8]uint32 { 123 | var w [68]uint32 124 | var w1 [64]uint32 125 | 126 | a, b, c, d, e, f, g, h := sm3.digest[0], sm3.digest[1], sm3.digest[2], sm3.digest[3], sm3.digest[4], sm3.digest[5], sm3.digest[6], sm3.digest[7] 127 | for len(msg) >= 64 { 128 | for i := 0; i < 16; i++ { 129 | w[i] = binary.BigEndian.Uint32(msg[4*i : 4*(i+1)]) 130 | } 131 | for i := 16; i < 68; i++ { 132 | w[i] = sm3.p1(w[i-16]^w[i-9]^sm3.leftRotate(w[i-3], 15)) ^ sm3.leftRotate(w[i-13], 7) ^ w[i-6] 133 | } 134 | for i := 0; i < 64; i++ { 135 | w1[i] = w[i] ^ w[i+4] 136 | } 137 | A, B, C, D, E, F, G, H := a, b, c, d, e, f, g, h 138 | for i := 0; i < 16; i++ { 139 | SS1 := sm3.leftRotate(sm3.leftRotate(A, 12)+E+sm3.leftRotate(0x79cc4519, uint32(i)), 7) 140 | SS2 := SS1 ^ sm3.leftRotate(A, 12) 141 | TT1 := sm3.ff0(A, B, C) + D + SS2 + w1[i] 142 | TT2 := sm3.gg0(E, F, G) + H + SS1 + w[i] 143 | D = C 144 | C = sm3.leftRotate(B, 9) 145 | B = A 146 | A = TT1 147 | H = G 148 | G = sm3.leftRotate(F, 19) 149 | F = E 150 | E = sm3.p0(TT2) 151 | } 152 | for i := 16; i < 64; i++ { 153 | SS1 := sm3.leftRotate(sm3.leftRotate(A, 12)+E+sm3.leftRotate(0x7a879d8a, uint32(i)), 7) 154 | SS2 := SS1 ^ sm3.leftRotate(A, 12) 155 | TT1 := sm3.ff1(A, B, C) + D + SS2 + w1[i] 156 | TT2 := sm3.gg1(E, F, G) + H + SS1 + w[i] 157 | D = C 158 | C = sm3.leftRotate(B, 9) 159 | B = A 160 | A = TT1 161 | H = G 162 | G = sm3.leftRotate(F, 19) 163 | F = E 164 | E = sm3.p0(TT2) 165 | } 166 | a ^= A 167 | b ^= B 168 | c ^= C 169 | d ^= D 170 | e ^= E 171 | f ^= F 172 | g ^= G 173 | h ^= H 174 | msg = msg[64:] 175 | } 176 | var digest [8]uint32 177 | digest[0], digest[1], digest[2], digest[3], digest[4], digest[5], digest[6], digest[7] = a, b, c, d, e, f, g, h 178 | return digest 179 | } 180 | 181 | // 创建哈希计算实例 182 | func New() hash.Hash { 183 | var sm3 SM3 184 | 185 | sm3.Reset() 186 | return &sm3 187 | } 188 | 189 | // BlockSize returns the hash's underlying block size. 190 | // The Write method must be able to accept any amount 191 | // of data, but it may operate more efficiently if all writes 192 | // are a multiple of the block size. 193 | func (sm3 *SM3) BlockSize() int { return 64 } 194 | 195 | // Size returns the number of bytes Sum will return. 196 | func (sm3 *SM3) Size() int { return 32 } 197 | 198 | // Reset clears the internal state by zeroing bytes in the state buffer. 199 | // This can be skipped for a newly-created hash state; the default zero-allocated state is correct. 200 | func (sm3 *SM3) Reset() { 201 | // Reset digest 202 | sm3.digest[0] = 0x7380166f 203 | sm3.digest[1] = 0x4914b2b9 204 | sm3.digest[2] = 0x172442d7 205 | sm3.digest[3] = 0xda8a0600 206 | sm3.digest[4] = 0xa96f30bc 207 | sm3.digest[5] = 0x163138aa 208 | sm3.digest[6] = 0xe38dee4d 209 | sm3.digest[7] = 0xb0fb0e4e 210 | 211 | sm3.length = 0 // Reset numberic states 212 | sm3.unhandleMsg = []byte{} 213 | } 214 | 215 | // Write (via the embedded io.Writer interface) adds more data to the running hash. 216 | // It never returns an error. 217 | func (sm3 *SM3) Write(p []byte) (int, error) { 218 | toWrite := len(p) 219 | sm3.length += uint64(len(p) * 8) 220 | msg := append(sm3.unhandleMsg, p...) 221 | nblocks := len(msg) / sm3.BlockSize() 222 | sm3.update(msg) 223 | // Update unhandleMsg 224 | sm3.unhandleMsg = msg[nblocks*sm3.BlockSize():] 225 | 226 | return toWrite, nil 227 | } 228 | 229 | // 返回SM3哈希算法摘要值 230 | // Sum appends the current hash to b and returns the resulting slice. 231 | // It does not change the underlying hash state. 232 | func (sm3 *SM3) Sum(in []byte) []byte { 233 | _, _ = sm3.Write(in) 234 | msg := sm3.pad() 235 | //Finalize 236 | digest := sm3.update2(msg) 237 | 238 | // save hash to in 239 | needed := sm3.Size() 240 | if cap(in)-len(in) < needed { 241 | newIn := make([]byte, len(in), len(in)+needed) 242 | copy(newIn, in) 243 | in = newIn 244 | } 245 | out := in[len(in) : len(in)+needed] 246 | for i := 0; i < 8; i++ { 247 | binary.BigEndian.PutUint32(out[i*4:], digest[i]) 248 | } 249 | return out 250 | 251 | } 252 | 253 | func Sm3Sum(data []byte) []byte { 254 | var sm3 SM3 255 | 256 | sm3.Reset() 257 | _, _ = sm3.Write(data) 258 | return sm3.Sum(nil) 259 | } 260 | -------------------------------------------------------------------------------- /x509/utils.go: -------------------------------------------------------------------------------- 1 | package x509 2 | 3 | import ( 4 | "bytes" 5 | "crypto" 6 | "crypto/rand" 7 | "crypto/rsa" 8 | "crypto/x509" 9 | "encoding/asn1" 10 | "encoding/hex" 11 | "encoding/pem" 12 | "errors" 13 | "math/big" 14 | 15 | "github.com/tjfoc/gmsm/sm2" 16 | ) 17 | 18 | func ReadPrivateKeyFromPem(privateKeyPem []byte, pwd []byte) (*sm2.PrivateKey, error) { 19 | var block *pem.Block 20 | block, _ = pem.Decode(privateKeyPem) 21 | if block == nil { 22 | return nil, errors.New("failed to decode private key") 23 | } 24 | priv, err := ParsePKCS8PrivateKey(block.Bytes, pwd) 25 | return priv, err 26 | } 27 | 28 | func WritePrivateKeyToPem(key *sm2.PrivateKey, pwd []byte) ([]byte, error) { 29 | var block *pem.Block 30 | der, err := MarshalSm2PrivateKey(key, pwd) //Convert private key to DER format 31 | if err != nil { 32 | return nil, err 33 | } 34 | if pwd != nil { 35 | block = &pem.Block{ 36 | Type: "ENCRYPTED PRIVATE KEY", 37 | Bytes: der, 38 | } 39 | } else { 40 | block = &pem.Block{ 41 | Type: "PRIVATE KEY", 42 | Bytes: der, 43 | } 44 | } 45 | certPem := pem.EncodeToMemory(block) 46 | return certPem, nil 47 | } 48 | 49 | func ReadPublicKeyFromPem(publicKeyPem []byte) (*sm2.PublicKey, error) { 50 | block, _ := pem.Decode(publicKeyPem) 51 | if block == nil || block.Type != "PUBLIC KEY" { 52 | return nil, errors.New("failed to decode public key") 53 | } 54 | return ParseSm2PublicKey(block.Bytes) 55 | } 56 | 57 | func WritePublicKeyToPem(key *sm2.PublicKey) ([]byte, error) { 58 | der, err := MarshalSm2PublicKey(key) //Convert publick key to DER format 59 | if err != nil { 60 | return nil, err 61 | } 62 | block := &pem.Block{ 63 | Type: "PUBLIC KEY", 64 | Bytes: der, 65 | } 66 | certPem := pem.EncodeToMemory(block) 67 | return certPem, nil 68 | } 69 | 70 | //DHex是sm2私钥的真正关键数值 71 | func ReadPrivateKeyFromHex(Dhex string) (*sm2.PrivateKey,error) { 72 | c := sm2.P256Sm2() 73 | d,err:=hex.DecodeString(Dhex) 74 | if err!=nil{ 75 | return nil,err 76 | } 77 | k:= new(big.Int).SetBytes(d) 78 | params := c.Params() 79 | one := new(big.Int).SetInt64(1) 80 | n := new(big.Int).Sub(params.N, one) 81 | if k.Cmp(n)>=0{ 82 | return nil,errors.New("privateKey's D is overflow.") 83 | } 84 | priv := new(sm2.PrivateKey) 85 | priv.PublicKey.Curve = c 86 | priv.D = k 87 | priv.PublicKey.X, priv.PublicKey.Y = c.ScalarBaseMult(k.Bytes()) 88 | return priv,nil 89 | } 90 | 91 | 92 | 93 | func WritePrivateKeyToHex(key *sm2.PrivateKey) string { 94 | return key.D.Text(16) 95 | } 96 | 97 | func ReadPublicKeyFromHex(Qhex string) (*sm2.PublicKey, error) { 98 | q,err:=hex.DecodeString(Qhex) 99 | if err!=nil{ 100 | return nil,err 101 | } 102 | if len(q)==65&&q[0]==byte(0x04){ 103 | q=q[1:] 104 | } 105 | if len(q)!=64{ 106 | return nil,errors.New("publicKey is not uncompressed.") 107 | } 108 | pub := new(sm2.PublicKey) 109 | pub.Curve = sm2.P256Sm2() 110 | pub.X = new(big.Int).SetBytes(q[:32]) 111 | pub.Y = new(big.Int).SetBytes(q[32:]) 112 | return pub, nil 113 | } 114 | 115 | 116 | func WritePublicKeyToHex(key *sm2.PublicKey) string { 117 | x := key.X.Bytes() 118 | y := key.Y.Bytes() 119 | if n := len(x); n < 32 { 120 | x = append(zeroByteSlice()[:32-n], x...) 121 | } 122 | if n := len(y); n < 32 { 123 | y = append(zeroByteSlice()[:32-n], y...) 124 | } 125 | c := []byte{} 126 | c = append(c, x...) 127 | c = append(c, y...) 128 | c = append([]byte{0x04}, c...) 129 | return hex.EncodeToString(c) 130 | } 131 | 132 | 133 | func ReadCertificateRequestFromPem(certPem []byte) (*CertificateRequest, error) { 134 | block, _ := pem.Decode(certPem) 135 | if block == nil { 136 | return nil, errors.New("failed to decode certificate request") 137 | } 138 | return ParseCertificateRequest(block.Bytes) 139 | } 140 | 141 | func CreateCertificateRequestToPem(template *CertificateRequest, signer crypto.Signer) ([]byte, error) { 142 | der, err := CreateCertificateRequest(rand.Reader, template, signer) 143 | if err != nil { 144 | return nil, err 145 | } 146 | block := &pem.Block{ 147 | Type: "CERTIFICATE REQUEST", 148 | Bytes: der, 149 | } 150 | certPem := pem.EncodeToMemory(block) 151 | return certPem, nil 152 | } 153 | 154 | func ReadCertificateFromPem(certPem []byte) (*Certificate, error) { 155 | block, _ := pem.Decode(certPem) 156 | if block == nil { 157 | return nil, errors.New("failed to decode certificate request") 158 | } 159 | return ParseCertificate(block.Bytes) 160 | } 161 | 162 | // CreateCertificate creates a new certificate based on a template. The 163 | // following members of template are used: SerialNumber, Subject, NotBefore, 164 | // NotAfter, KeyUsage, ExtKeyUsage, UnknownExtKeyUsage, BasicConstraintsValid, 165 | // IsCA, MaxPathLen, SubjectKeyId, DNSNames, PermittedDNSDomainsCritical, 166 | // PermittedDNSDomains, SignatureAlgorithm. 167 | // 168 | // The certificate is signed by parent. If parent is equal to template then the 169 | // certificate is self-signed. The parameter pub is the public key of the 170 | // signee and priv is the private key of the signer. 171 | // 172 | // The returned slice is the certificate in DER encoding. 173 | // 174 | // All keys types that are implemented via crypto.Signer are supported (This 175 | // includes *rsa.PublicKey and *ecdsa.PublicKey.) 176 | func CreateCertificate(template, parent *Certificate, publicKey *sm2.PublicKey, signer crypto.Signer) ([]byte, error) { 177 | if template.SerialNumber == nil { 178 | return nil, errors.New("x509: no SerialNumber given") 179 | } 180 | 181 | hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(signer.Public(), template.SignatureAlgorithm) 182 | if err != nil { 183 | return nil, err 184 | } 185 | 186 | publicKeyBytes, publicKeyAlgorithm, err := marshalPublicKey(publicKey) 187 | if err != nil { 188 | return nil, err 189 | } 190 | 191 | asn1Issuer, err := subjectBytes(parent) 192 | if err != nil { 193 | return nil, err 194 | } 195 | 196 | asn1Subject, err := subjectBytes(template) 197 | if err != nil { 198 | return nil, err 199 | } 200 | 201 | if !bytes.Equal(asn1Issuer, asn1Subject) && len(parent.SubjectKeyId) > 0 { 202 | template.AuthorityKeyId = parent.SubjectKeyId 203 | } 204 | 205 | extensions, err := buildExtensions(template) 206 | if err != nil { 207 | return nil, err 208 | } 209 | encodedPublicKey := asn1.BitString{BitLength: len(publicKeyBytes) * 8, Bytes: publicKeyBytes} 210 | c := tbsCertificate{ 211 | Version: 2, 212 | SerialNumber: template.SerialNumber, 213 | SignatureAlgorithm: signatureAlgorithm, 214 | Issuer: asn1.RawValue{FullBytes: asn1Issuer}, 215 | Validity: validity{template.NotBefore.UTC(), template.NotAfter.UTC()}, 216 | Subject: asn1.RawValue{FullBytes: asn1Subject}, 217 | PublicKey: publicKeyInfo{nil, publicKeyAlgorithm, encodedPublicKey}, 218 | Extensions: extensions, 219 | } 220 | 221 | tbsCertContents, err := asn1.Marshal(c) 222 | if err != nil { 223 | return nil, err 224 | } 225 | 226 | c.Raw = tbsCertContents 227 | 228 | digest := tbsCertContents 229 | switch template.SignatureAlgorithm { 230 | case SM2WithSM3, SM2WithSHA1, SM2WithSHA256: 231 | break 232 | default: 233 | h := hashFunc.New() 234 | h.Write(tbsCertContents) 235 | digest = h.Sum(nil) 236 | } 237 | 238 | var signerOpts crypto.SignerOpts 239 | signerOpts = hashFunc 240 | if template.SignatureAlgorithm != 0 && template.SignatureAlgorithm.isRSAPSS() { 241 | signerOpts = &rsa.PSSOptions{ 242 | SaltLength: rsa.PSSSaltLengthEqualsHash, 243 | Hash: crypto.Hash(hashFunc), 244 | } 245 | } 246 | 247 | var signature []byte 248 | signature, err = signer.Sign(rand.Reader, digest, signerOpts) 249 | if err != nil { 250 | return nil, err 251 | } 252 | return asn1.Marshal(certificate{ 253 | nil, 254 | c, 255 | signatureAlgorithm, 256 | asn1.BitString{Bytes: signature, BitLength: len(signature) * 8}, 257 | }) 258 | } 259 | 260 | // CreateCertificateToPem creates a new certificate based on a template and 261 | // encodes it to PEM format. It uses CreateCertificate to create certificate 262 | // and returns its PEM format. 263 | func CreateCertificateToPem(template, parent *Certificate, pubKey *sm2.PublicKey, signer crypto.Signer) ([]byte, error) { 264 | der, err := CreateCertificate(template, parent, pubKey, signer) 265 | if err != nil { 266 | return nil, err 267 | } 268 | block := &pem.Block{ 269 | Type: "CERTIFICATE", 270 | Bytes: der, 271 | } 272 | certPem := pem.EncodeToMemory(block) 273 | return certPem, nil 274 | } 275 | 276 | func ParseSm2CertifateToX509(asn1data []byte) (*x509.Certificate, error) { 277 | sm2Cert, err := ParseCertificate(asn1data) 278 | if err != nil { 279 | return nil, err 280 | } 281 | return sm2Cert.ToX509Certificate(), nil 282 | } 283 | // 32byte 284 | func zeroByteSlice() []byte { 285 | return []byte{ 286 | 0, 0, 0, 0, 287 | 0, 0, 0, 0, 288 | 0, 0, 0, 0, 289 | 0, 0, 0, 0, 290 | 0, 0, 0, 0, 291 | 0, 0, 0, 0, 292 | 0, 0, 0, 0, 293 | 0, 0, 0, 0, 294 | } 295 | } 296 | -------------------------------------------------------------------------------- /sm4/sm4_gcm.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Hyperledger-TWGC All Rights Reserved. 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | 15 | writed by Zhiwei Yan, 2020 Oct 16 | */ 17 | 18 | package sm4 19 | 20 | import ( 21 | "errors" 22 | "strconv" 23 | ) 24 | 25 | // Sm4GCM SM4 GCM 加解密模式 26 | // Paper: The Galois/Counter Mode of Operation (GCM) David A. Mcgrew,John Viega .2004. 27 | // key: 对称加密密钥 28 | // IV: IV向量 29 | // in: 30 | // A: 附加的可鉴别数据(ADD) 31 | // mode: true - 加密; false - 解密验证 32 | // 33 | // return: 密文C, 鉴别标签T, 错误 34 | func Sm4GCM(key []byte, IV, in, A []byte, mode bool) ([]byte, []byte, error) { 35 | if len(key) != BlockSize { 36 | return nil, nil, errors.New("SM4: invalid key size " + strconv.Itoa(len(key))) 37 | } 38 | if mode { 39 | C, T := GCMEncrypt(key, IV, in, A) 40 | return C, T, nil 41 | } else { 42 | P, _T := GCMDecrypt(key, IV, in, A) 43 | return P, _T, nil 44 | } 45 | } 46 | 47 | // GetH 对“0”分组的加密得到 GHASH泛杂凑函数的子密钥 48 | // key: 对称密钥 49 | // return: GHASH泛杂凑函数的子密钥 50 | func GetH(key []byte) (H []byte) { 51 | c, err := NewCipher(key) 52 | if err != nil { 53 | panic(err) 54 | } 55 | 56 | zores := make([]byte, BlockSize) 57 | H = make([]byte, BlockSize) 58 | c.Encrypt(H, zores) 59 | return H 60 | } 61 | 62 | //ut = a + b 63 | func addition(a, b []byte) (out []byte) { 64 | Len := len(a) 65 | if Len != len(b) { 66 | return nil 67 | } 68 | out = make([]byte, Len) 69 | for i := 0; i < Len; i++ { 70 | out[i] = a[i] ^ b[i] 71 | } 72 | return out 73 | } 74 | 75 | func Rightshift(V []byte) { 76 | n := len(V) 77 | for i := n - 1; i >= 0; i-- { 78 | V[i] = V[i] >> 1 79 | if i != 0 { 80 | V[i] = ((V[i-1] & 0x01) << 7) | V[i] 81 | } 82 | } 83 | } 84 | 85 | func findYi(Y []byte, index int) int { 86 | var temp byte 87 | i := uint(index) 88 | temp = Y[i/8] 89 | temp = temp >> (7 - i%8) 90 | if temp&0x01 == 1 { 91 | return 1 92 | } else { 93 | return 0 94 | } 95 | } 96 | 97 | func multiplication(X, Y []byte) (Z []byte) { 98 | 99 | R := make([]byte, BlockSize) 100 | R[0] = 0xe1 101 | Z = make([]byte, BlockSize) 102 | V := make([]byte, BlockSize) 103 | copy(V, X) 104 | for i := 0; i <= 127; i++ { 105 | if findYi(Y, i) == 1 { 106 | Z = addition(Z, V) 107 | } 108 | if V[BlockSize-1]&0x01 == 0 { 109 | Rightshift(V) 110 | } else { 111 | Rightshift(V) 112 | V = addition(V, R) 113 | } 114 | } 115 | return Z 116 | } 117 | 118 | func GHASH(H []byte, A []byte, C []byte) (X []byte) { 119 | 120 | calculm_v := func(m, v int) (int, int) { 121 | if m == 0 && v != 0 { 122 | m = 1 123 | v = v * 8 124 | } else if m != 0 && v == 0 { 125 | v = BlockSize * 8 126 | } else if m != 0 && v != 0 { 127 | m = m + 1 128 | v = v * 8 129 | } else { //m==0 && v==0 130 | m = 1 131 | v = 0 132 | } 133 | return m, v 134 | } 135 | m := len(A) / BlockSize 136 | v := len(A) % BlockSize 137 | m, v = calculm_v(m, v) 138 | 139 | n := len(C) / BlockSize 140 | u := (len(C) % BlockSize) 141 | n, u = calculm_v(n, u) 142 | 143 | //i=0 144 | X = make([]byte, BlockSize*(m+n+2)) //X0 = 0 145 | for i := 0; i < BlockSize; i++ { 146 | X[i] = 0x00 147 | } 148 | 149 | //i=1...m-1 150 | for i := 1; i <= m-1; i++ { 151 | copy(X[i*BlockSize:i*BlockSize+BlockSize], multiplication(addition(X[(i-1)*BlockSize:(i-1)*BlockSize+BlockSize], A[(i-1)*BlockSize:(i-1)*BlockSize+BlockSize]), H)) //A 1-->m-1 对于数组来说是 0-->m-2 152 | } 153 | 154 | //i=m 155 | zeros := make([]byte, (128-v)/8) 156 | Am := make([]byte, v/8) 157 | copy(Am[:], A[(m-1)*BlockSize:]) 158 | Am = append(Am, zeros...) 159 | copy(X[m*BlockSize:m*BlockSize+BlockSize], multiplication(addition(X[(m-1)*BlockSize:(m-1)*BlockSize+BlockSize], Am), H)) 160 | 161 | //i=m+1...m+n-1 162 | for i := m + 1; i <= (m + n - 1); i++ { 163 | copy(X[i*BlockSize:i*BlockSize+BlockSize], multiplication(addition(X[(i-1)*BlockSize:(i-1)*BlockSize+BlockSize], C[(i-m-1)*BlockSize:(i-m-1)*BlockSize+BlockSize]), H)) 164 | } 165 | 166 | //i=m+n 167 | zeros = make([]byte, (128-u)/8) 168 | Cn := make([]byte, u/8) 169 | copy(Cn[:], C[(n-1)*BlockSize:]) 170 | Cn = append(Cn, zeros...) 171 | copy(X[(m+n)*BlockSize:(m+n)*BlockSize+BlockSize], multiplication(addition(X[(m+n-1)*BlockSize:(m+n-1)*BlockSize+BlockSize], Cn), H)) 172 | 173 | //i=m+n+1 174 | var lenAB []byte 175 | calculateLenToBytes := func(len int) []byte { 176 | data := make([]byte, 8) 177 | data[0] = byte((len >> 56) & 0xff) 178 | data[1] = byte((len >> 48) & 0xff) 179 | data[2] = byte((len >> 40) & 0xff) 180 | data[3] = byte((len >> 32) & 0xff) 181 | data[4] = byte((len >> 24) & 0xff) 182 | data[5] = byte((len >> 16) & 0xff) 183 | data[6] = byte((len >> 8) & 0xff) 184 | data[7] = byte((len >> 0) & 0xff) 185 | return data 186 | } 187 | lenAB = append(lenAB, calculateLenToBytes(len(A))...) 188 | lenAB = append(lenAB, calculateLenToBytes(len(C))...) 189 | copy(X[(m+n+1)*BlockSize:(m+n+1)*BlockSize+BlockSize], multiplication(addition(X[(m+n)*BlockSize:(m+n)*BlockSize+BlockSize], lenAB), H)) 190 | return X[(m+n+1)*BlockSize : (m+n+1)*BlockSize+BlockSize] 191 | } 192 | 193 | // GetY0 生成初始的计数器时钟J0 194 | // 195 | // H: GHASH自密钥 196 | // IV: IV向量 197 | // return: 初始的计数器时钟(J0) 198 | func GetY0(H, IV []byte) []byte { 199 | if len(IV)*8 == 96 { 200 | zero31one1 := []byte{0x00, 0x00, 0x00, 0x01} 201 | IV = append(IV, zero31one1...) 202 | return IV 203 | } else { 204 | return GHASH(H, []byte{}, IV) 205 | } 206 | } 207 | 208 | func incr(n int, Y_i []byte) (Y_ii []byte) { 209 | 210 | Y_ii = make([]byte, BlockSize*n) 211 | copy(Y_ii, Y_i) 212 | 213 | addYone := func(yi, yii []byte) { 214 | copy(yii[:], yi[:]) 215 | 216 | Len := len(yi) 217 | var rc byte = 0x00 218 | for i := Len - 1; i >= 0; i-- { 219 | if i == Len-1 { 220 | if yii[i] < 0xff { 221 | yii[i] = yii[i] + 0x01 222 | rc = 0x00 223 | } else { 224 | yii[i] = 0x00 225 | rc = 0x01 226 | } 227 | } else { 228 | if yii[i]+rc < 0xff { 229 | yii[i] = yii[i] + rc 230 | rc = 0x00 231 | } else { 232 | yii[i] = 0x00 233 | rc = 0x01 234 | } 235 | } 236 | } 237 | } 238 | for i := 1; i < n; i++ { //2^32 239 | addYone(Y_ii[(i-1)*BlockSize:(i-1)*BlockSize+BlockSize], Y_ii[i*BlockSize:i*BlockSize+BlockSize]) 240 | } 241 | return Y_ii 242 | } 243 | 244 | func MSB(len int, S []byte) (out []byte) { 245 | return S[:len/8] 246 | } 247 | 248 | // GCMEncrypt 可鉴别加密函数 (GCM-AE(k)) 249 | // K: 对称密钥 250 | // IV: IV向量 251 | // P: 明文 252 | // A: 附加的鉴别数据 253 | // 254 | // return: 密文, 鉴别标签 255 | func GCMEncrypt(K, IV, P, A []byte) (C, T []byte) { 256 | calculm_v := func(m, v int) (int, int) { 257 | if m == 0 && v != 0 { 258 | m = 1 259 | v = v * 8 260 | } else if m != 0 && v == 0 { 261 | v = BlockSize * 8 262 | } else if m != 0 && v != 0 { 263 | m = m + 1 264 | v = v * 8 265 | } else { //m==0 && v==0 266 | m = 1 267 | v = 0 268 | } 269 | return m, v 270 | } 271 | n := len(P) / BlockSize 272 | u := len(P) % BlockSize 273 | n, u = calculm_v(n, u) 274 | 275 | // a) 通过对“0”分组的加密得到 GHASH泛杂凑函数的子密钥 276 | H := GetH(K) 277 | 278 | Y0 := GetY0(H, IV) 279 | 280 | Y := make([]byte, BlockSize*(n+1)) 281 | Y = incr(n+1, Y0) 282 | c, err := NewCipher(K) 283 | if err != nil { 284 | panic(err) 285 | } 286 | Enc := make([]byte, BlockSize) 287 | C = make([]byte, len(P)) 288 | 289 | //i=1...n-1 290 | for i := 1; i <= n-1; i++ { 291 | c.Encrypt(Enc, Y[i*BlockSize:i*BlockSize+BlockSize]) 292 | 293 | copy(C[(i-1)*BlockSize:(i-1)*BlockSize+BlockSize], addition(P[(i-1)*BlockSize:(i-1)*BlockSize+BlockSize], Enc)) 294 | } 295 | 296 | //i=n 297 | c.Encrypt(Enc, Y[n*BlockSize:n*BlockSize+BlockSize]) 298 | out := MSB(u, Enc) 299 | copy(C[(n-1)*BlockSize:], addition(P[(n-1)*BlockSize:], out)) 300 | 301 | c.Encrypt(Enc, Y0) 302 | 303 | t := 128 304 | T = MSB(t, addition(Enc, GHASH(H, A, C))) 305 | return C, T 306 | } 307 | 308 | func GCMDecrypt(K, IV, C, A []byte) (P, _T []byte) { 309 | calculm_v := func(m, v int) (int, int) { 310 | if m == 0 && v != 0 { 311 | m = 1 312 | v = v * 8 313 | } else if m != 0 && v == 0 { 314 | v = BlockSize * 8 315 | } else if m != 0 && v != 0 { 316 | m = m + 1 317 | v = v * 8 318 | } else { //m==0 && v==0 319 | m = 1 320 | v = 0 321 | } 322 | return m, v 323 | } 324 | 325 | H := GetH(K) 326 | 327 | Y0 := GetY0(H, IV) 328 | 329 | Enc := make([]byte, BlockSize) 330 | c, err := NewCipher(K) 331 | if err != nil { 332 | panic(err) 333 | } 334 | c.Encrypt(Enc, Y0) 335 | t := 128 336 | _T = MSB(t, addition(Enc, GHASH(H, A, C))) 337 | 338 | n := len(C) / BlockSize 339 | u := len(C) % BlockSize 340 | n, u = calculm_v(n, u) 341 | Y := make([]byte, BlockSize*(n+1)) 342 | Y = incr(n+1, Y0) 343 | 344 | P = make([]byte, BlockSize*n) 345 | for i := 1; i <= n; i++ { 346 | c.Encrypt(Enc, Y[i*BlockSize:i*BlockSize+BlockSize]) 347 | copy(P[(i-1)*BlockSize:(i-1)*BlockSize+BlockSize], addition(C[(i-1)*BlockSize:(i-1)*BlockSize+BlockSize], Enc)) 348 | } 349 | 350 | c.Encrypt(Enc, Y[n*BlockSize:n*BlockSize+BlockSize]) 351 | out := MSB(u, Enc) 352 | copy(P[(n-1)*BlockSize:], addition(C[(n-1)*BlockSize:], out)) 353 | 354 | return P, _T 355 | } 356 | -------------------------------------------------------------------------------- /gmtls/websvr/README.md: -------------------------------------------------------------------------------- 1 | # TLS/GMSSL 服务端协议自适应 2 | 3 | 4 | 5 | - [TLS/GMSSL 服务端协议自适应](#tlsgmssl-服务端协议自适应) 6 | - [服务端 GMSSL/TLS 工作逻辑](#服务端-gmssltls-工作逻辑) 7 | - [GMSSL/TLS 自动切换模式](#gmssltls-自动切换模式) 8 | - [TCLP 双向身份认证](#tclp-双向身份认证) 9 | - [服务端配置](#服务端配置) 10 | - [客户端配置](#客户端配置) 11 | - [国密HTTPS客户端](#国密https客户端) 12 | - [HTTPS 单向身份认证](#https-单向身份认证) 13 | - [HTTPS 双向身份认证](#https-双向身份认证) 14 | - [TLCP GCM模式](#tlcp-gcm模式) 15 | - [客户端 GCM配置](#客户端-gcm配置) 16 | - [关于 TLCP AEAD随机数](#关于-tlcp-aead随机数) 17 | 18 | 19 | 20 | 21 | 目录结构说明: 22 | 23 | ``` 24 | ├─certs // 证书以及密钥 25 | ├─websvr_test //HTTP服务端/客户端测试Demo 26 | └─websvr //协议自适应实现 27 | ``` 28 | 29 | ## 服务端 GMSSL/TLS 工作逻辑 30 | 31 | ![autoswitchlogic](./img/autoswitchlogic.png) 32 | 33 | 34 | 通过配置`gmtls.Config` 对象提供自动切换相关的配置,创建`gmtls.Conn`。 35 | 36 | 在对`gmtls.Conn`的`Read/Wirte`时将会触发握手行为`HandShake`。 37 | 38 | `HandShake`会根据用户配置参数,判断需要使用 GMSSL、TLS、GMSSL/TLS 三种工作模式中的哪一种, 39 | 然后进入到相应的工作模式中运行。 40 | 41 | - **TLS工作模式**: 42 | - 运行`serverHandshake` 进入TLS握手。 43 | - 创建TLS握手上下文`serverHandshakeState`。 44 | - 读取并处理 来自于客户端的ClientHello 消息。 45 | - 进入 TLS握手流程。 46 | - **GMSSL工作模式**: 47 | - 运行`serverHandshakeGM` 进入GMSSL握手。 48 | - 创建TLS握手上下文`serverHandshakeStateGM`。 49 | - 读取并处理 来自于客户端的ClientHello 消息。 50 | - 进入 GMSSL握手流程。 51 | - **GMSSL/TLS工作模式**: 52 | - 运行`serverHandshakeAutoSwitch` 进入自动切换的握手模式。 53 | - 读取来自于客户端的ClientHello 消息。 54 | - 分析处理ClientHello,根据客户端协议版本。 55 | - 根据协议版本,选择使用具体握手方式: 56 | - GMSSL: 创建上下文`serverHandshakeStateGM`,进入GMSSL握手流程。 57 | - TLS: 创建上下文`serverHandshakeState`,进入TLS握手流程。 58 | 59 | 60 | 在GMSSL/TLS模式的服务端运行过程中,如何根据客户端版本选择需要使用的证书以及密钥? 61 | 62 | 自动切换模式,同时需要为服务端提供2份证书与密钥对(一份用于标准的TLS、一份用于GMSSL), 63 | 在运行过程需要使用到`gmtls.Config#GetCertificate`方法来根据客户端的版本选择出合适的 64 | 证书密钥对,即在客户端版本是GMSSL的时候返回SM2签名证书密钥对;在客户端版本是标准的TLS时 65 | 返还RSA/ECC的证书密钥对,以次来动态适应不同客户端的连接需求。 66 | 针对于GMSSL特殊的双证书需求,特别为`gmtls.Config`增加了一个方法`gmtls.Config#GetKECertificate` 67 | 通过该方法来提供GMSSL密钥交换过程中使用密钥对。 68 | 69 | 更多细节实现见: [auto_handshake_server](../auto_handshake_server.go) 70 | 71 | ## GMSSL/TLS 自动切换模式 72 | 73 | 快速开始: 74 | 75 | 1. 准备 RSA、SM2签名、SM2加密,证书以及密钥对。 76 | 2. 调用`gmtls.NewBasicAutoSwitchConfig`构造基础的配置对象。 77 | 3. Use it. 78 | 79 | ```go 80 | func main() { 81 | config, err := gmtls.NewBasicAutoSwitchConfig(&sigCert, &encCert, &rsaKeypair) 82 | if err != nil { 83 | panic(err) 84 | } 85 | 86 | ln, err := gmtls.Listen("tcp", ":443", config) 87 | if err != nil { 88 | panic(err) 89 | } 90 | defer ln.Close() 91 | 92 | http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) { 93 | fmt.Fprintf(writer, "hello\n") 94 | }) 95 | err = http.Serve(ln, nil) 96 | if err != nil { 97 | panic(err) 98 | } 99 | } 100 | ``` 101 | 102 | 103 | 详细服务端的配置流程如下: 104 | 105 | 1. 准备: 106 | - SM2签名密钥对、证书:`sigCert` 107 | - SM2加密密钥对、证书:`encCert` 108 | - RSA/ECC加密密钥对、证书:`rsaKeypair` 109 | 2. 创建一个实现`gmtls.Config#GetCertificate`方法签名的方法,方法需要根据支持的签名类型: 110 | - 含有GMSSL版本:返回SM2签名证书密钥对(`sigCert`)。 111 | - 不含有GMSSL版本:返回RSA签名证书密钥对(`rsaKeypair`)。 112 | 3. 创建一个实现`gmtls.Config#GetKECertificate`方法签名的方法,固定返回SM2加密证书密钥对(`encCert`)。 113 | 4. 创建`GMSupport`并启用,自动切换模式。 114 | 5. 创建`gmtls.Config`对象,接下就可以启动服务端实现自动切换功能。 115 | 116 | ```go 117 | fncGetSignCertKeypair := func(info *gmtls.ClientHelloInfo) (*gmtls.Certificate, error) { 118 | gmFlag := false 119 | // 检查支持协议中是否包含GMSSL 120 | for _, v := range info.SupportedVersions { 121 | if v == gmtls.VersionGMSSL { 122 | gmFlag = true 123 | break 124 | } 125 | } 126 | if gmFlag { 127 | return &sigCert, nil 128 | } else { 129 | return &rsaKeypair, nil 130 | } 131 | } 132 | 133 | fncGetEncCertKeypair := func(info *gmtls.ClientHelloInfo) (*gmtls.Certificate, error) { 134 | return &encCert, nil 135 | } 136 | support := gmtls.NewGMSupport() 137 | support.EnableMixMode() 138 | config := &gmtls.Config{ 139 | GMSupport: support, 140 | GetCertificate: fncGetSignCertKeypair, 141 | GetKECertificate: fncGetEncCertKeypair, 142 | } 143 | ``` 144 | 145 | > 更多细节请参考: [HTTP over GMTLS/TLS Server Demo](./websvr.go) 146 | 147 | 148 | ## TCLP 双向身份认证 149 | 150 | ### 服务端配置 151 | 152 | 1. 设置启用国密TLCP支持。 153 | 2. 配置服务端签名证书密钥和加密证书密钥。 154 | 3. 设置服务端开启双向身份认证,并要求验证客户端证书。 155 | 4. 配置根证书链,用于验证客户端证书。 156 | 157 | ```go 158 | config := &gmtls.Config{ 159 | GMSupport: gmtls.NewGMSupport(), 160 | Certificates: []gmtls.Certificate{sigCert, encCert}, 161 | ClientAuth: gmtls.RequireAndVerifyClientCert, 162 | ClientCAs: certPool, 163 | } 164 | ``` 165 | 166 | > 更多细节请参考: 167 | > 168 | > - [TLCP服务端 双向身份认证配置 Demo websvr.go #loadServerMutualTLCPAuthConfig](./websvr.go) 169 | 170 | 171 | ### 客户端配置 172 | 173 | 1. 设置启用国密TLCP支持。 174 | 2. 配置双向身份认证的客户端方的签名证书和密钥对。 175 | 3. 提供验证服务端证书的根证书链。 176 | 4. 设置需要进行安全校验。 177 | 178 | 例如: 179 | 180 | ```go 181 | config := &gmtls.Config{ 182 | GMSupport: gmtls.NewGMSupport(), 183 | RootCAs: certPool, 184 | Certificates: []gmtls.Certificate{authKeypair}, 185 | InsecureSkipVerify: false, 186 | } 187 | ``` 188 | 189 | > 更多细节请参考: 190 | > 191 | > - [TLCP客户端 双向身份认证配置 Demo websvr.go #bothAuthConfig](./websvr.go) 192 | 193 | 194 | ## 国密HTTPS客户端 195 | 196 | 为了简化HTTPS客户端的构造`gmtls`包提供下面构造方法: 197 | 198 | - 创建单向身份认证HTTPS客户端:`gmtls.NewHTTPSClient(*x509.CertPool)` 199 | - 创建双向身份认证HTTPS客户端:`gmtls.NewAuthHTTPSClient(*x509.CertPool, *gmtls.Certificate)` 200 | - 创建定制化的TLS连接的HTTPS客户端:`gmtls.NewCustomHTTPSClient(*gmtls.Config)` 201 | 202 | ### HTTPS 单向身份认证 203 | 204 | 单向身份认证客户端,只只验证服务器证书有效性,服务端不对客户端进行身份认证。 205 | 206 | 该模式下进行国密HTTPS的调用你需要: 207 | 208 | 1. 提供根证书链。 209 | 2. 构造HTTP客户端。 210 | 3. 调用API访问HTTPS。 211 | 212 | ```go 213 | package main 214 | 215 | import ( 216 | "github.com/tjfoc/gmsm/gmtls" 217 | "github.com/tjfoc/gmsm/x509" 218 | "io/ioutil" 219 | ) 220 | 221 | func main() { 222 | // 1. 提供根证书链 223 | certPool := x509.NewCertPool() 224 | cacert, err := ioutil.ReadFile("websvr/certs/SM2_CA.cer") 225 | if err != nil { 226 | panic(err) 227 | } 228 | certPool.AppendCertsFromPEM(cacert) 229 | // 2. 构造HTTP客户端 230 | httpClient := gmtls.NewHTTPSClient(certPool) 231 | // 3. 调用API访问HTTPS 232 | response, err := httpClient.Get("https://localhost:443") 233 | if err != nil { 234 | panic(err) 235 | } 236 | defer response.Body.Close() 237 | // 使用 response 做你需要的事情... 238 | } 239 | ``` 240 | 241 | 更多细节见 [gmsm/http_client_test.go#TestNewHTTPSClient2](../http_client_test.go) 242 | 243 | ### HTTPS 双向身份认证 244 | 245 | 双向身份认证,在服务端开启了对客户端的身份认证情况下,国密SSL通行就需要进行双向身份认证。 246 | 247 | 该模式下进行国密HTTPS的调用你需要: 248 | 249 | 1. 提供根证书链。 250 | 2. 提供客户端认证证书、密钥对。 251 | 3. 构造HTTP客户端。 252 | 4. 调用API访问HTTPS。 253 | 254 | ```go 255 | package main 256 | 257 | import ( 258 | "github.com/tjfoc/gmsm/gmtls" 259 | "github.com/tjfoc/gmsm/x509" 260 | "io/ioutil" 261 | ) 262 | 263 | func main() { 264 | // 1. 提供根证书链 265 | certPool := x509.NewCertPool() 266 | cacert, err := ioutil.ReadFile("websvr/certs/SM2_CA.cer") 267 | if err != nil { 268 | panic(err) 269 | } 270 | certPool.AppendCertsFromPEM(cacert) 271 | // 2. 提供客户端认证证书、密钥对。 272 | clientAuthCert, err := gmtls.LoadX509KeyPair("websvr/certs/sm2_auth_cert.cer", "websvr/certs/sm2_auth_key.pem") 273 | // 3. 构造HTTP客户端。 274 | httpClient := gmtls.NewAuthHTTPSClient(certPool, &clientAuthCert) 275 | // 4. 调用API访问HTTPS。 276 | response, err := httpClient.Get("https://localhost:443") 277 | if err != nil { 278 | panic(err) 279 | } 280 | defer response.Body.Close() 281 | // 使用 response 做你需要的事情... 282 | } 283 | ``` 284 | 285 | 更多细节见 [gmsm/http_client_test.go#TestSimpleNewAuthHTTPSClient](../http_client_test.go) 286 | 287 | ## TLCP GCM模式 288 | 289 | 《GBT 38636-2020 信息安全技术 传输层密码协议(TLCP)》协议中增加了GCM可鉴别加密模式相关的系列密码套件。 290 | 291 | 以`ECC_SM4_GCM_SM3` 密码套件为例,该套件使用SM4算法GCM可鉴别加密模式,替换了“SM4 CBC模式 + SM3 HMAC”,其余保持不变。 292 | 293 | GCM模式下: 294 | 295 | - 密文数据结构和生成规则详见: 《GBT 38636-2020》 6.3.3.4.4 认证加密算法的数据处理 296 | - 实现随机数实现细节见:RFC 5116 (AES_GCM 参考 RFC 5288) 297 | 298 | 299 | 如何使用? 300 | 301 | - 目前客户端和服务端均支持 `ECC_SM4_GCM_SM3` 与 `ECC_SM4_CBC_SM3` 密码套件。 302 | - 服务端:无需而外配置。 303 | - 客户端:目前客户单默认使用`ECC_SM4_CBC_SM3`密码套件,需要手动配置才可以使用 `ECC_SM4_GCM_SM3`套件。 304 | 305 | 目前支持TLCP密码套件: 306 | 307 | - `ECC_SM4_GCM_SM3` 308 | - `ECC_SM4_CBC_SM3` 309 | - `ECDHE_SM4_CBC_SM3` 310 | - `ECDHE_SM4_GCM_SM3` 311 | 312 | ### 客户端 GCM配置 313 | 314 | 以单向身份认证举例,只需要在连接配置中增加响应的算法,将GCM模式套件放在数组较前面的位置就可以。 315 | 316 | 示例如下: 317 | 318 | ```go 319 | package main 320 | 321 | import ( 322 | "github.com/tjfoc/gmsm/gmtls" 323 | "github.com/tjfoc/gmsm/x509" 324 | "io/ioutil" 325 | "log" 326 | ) 327 | 328 | func main() { 329 | // 信任的根证书 330 | certPool := x509.NewCertPool() 331 | cacert, err := ioutil.ReadFile("root.cer") 332 | if err != nil { 333 | log.Fatal(err) 334 | } 335 | certPool.AppendCertsFromPEM(cacert) 336 | cert, err := gmtls.LoadX509KeyPair("sm2_cli.cer", "sm2_cli.pem") 337 | 338 | config := &gmtls.Config{ 339 | GMSupport: &gmtls.GMSupport{}, 340 | RootCAs: certPool, 341 | Certificates: []gmtls.Certificate{cert}, 342 | // 设置GCM模式套件放在前面 343 | CipherSuites: []uint16{gmtls.GMTLS_ECC_SM4_GCM_SM3, gmtls.GMTLS_ECC_SM4_CBC_SM3}, 344 | } 345 | 346 | conn, err := gmtls.Dial("tcp", "localhost:50052", config) 347 | if err != nil { 348 | panic(err) 349 | } 350 | defer conn.Close() 351 | 352 | // 对 conn 读取或写入 353 | } 354 | ``` 355 | 356 | ### 关于 TLCP AEAD随机数 357 | 358 | 该套件采用 显式 和 隐式 随机数构造,AEAD随机数(Nonce),总长12字节,4字节隐式随机数、8字节显式部分。 359 | 360 | ```txt 361 | +---------------------+----------------------------------+ 362 | | Fixed(4byte) | Counter(8byte) | 363 | +---------------------+----------------------------------+ 364 | <---- 隐式随机数 ---> <------------ 显式部分 ------------> 365 | ``` 366 | 367 | - 隐式随机数为: 工作密钥中的 客户端写IV(`client_write_IV `) 或 服务端写IV(`server_write_IV`)。 368 | - 显式部分为: 数据包序号(`seq_num`),也就是`GenericAEADCipher.nonce_explicit`字段。 369 | 370 | > 详见 RFC 5116 3.2. Recommended Nonce Formation 371 | 372 | AEAD SM4 与 AEAD AES 128 实现一致。 373 | 374 | --------------------------------------------------------------------------------