| // Copyright 2017 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // +build linux,amd64 |
| // +build !android |
| // +build !cmd_go_bootstrap |
| // +build !msan |
| |
| package boring |
| |
| // #include "goboringcrypto.h" |
| import "C" |
| import ( |
| "crypto" |
| "crypto/subtle" |
| "errors" |
| "hash" |
| "math/big" |
| "runtime" |
| "strconv" |
| "unsafe" |
| ) |
| |
| func GenerateKeyRSA(bits int) (N, E, D, P, Q, Dp, Dq, Qinv *big.Int, err error) { |
| bad := func(e error) (N, E, D, P, Q, Dp, Dq, Qinv *big.Int, err error) { |
| return nil, nil, nil, nil, nil, nil, nil, nil, e |
| } |
| |
| key := C._goboringcrypto_RSA_new() |
| if key == nil { |
| return bad(fail("RSA_new")) |
| } |
| defer C._goboringcrypto_RSA_free(key) |
| |
| if C._goboringcrypto_RSA_generate_key_fips(key, C.int(bits), nil) == 0 { |
| return bad(fail("RSA_generate_key_fips")) |
| } |
| |
| var n, e, d, p, q, dp, dq, qinv *C.GO_BIGNUM |
| C._goboringcrypto_RSA_get0_key(key, &n, &e, &d) |
| C._goboringcrypto_RSA_get0_factors(key, &p, &q) |
| C._goboringcrypto_RSA_get0_crt_params(key, &dp, &dq, &qinv) |
| return bnToBig(n), bnToBig(e), bnToBig(d), bnToBig(p), bnToBig(q), bnToBig(dp), bnToBig(dq), bnToBig(qinv), nil |
| } |
| |
| type PublicKeyRSA struct { |
| key *C.GO_RSA |
| } |
| |
| func NewPublicKeyRSA(N, E *big.Int) (*PublicKeyRSA, error) { |
| key := C._goboringcrypto_RSA_new() |
| if key == nil { |
| return nil, fail("RSA_new") |
| } |
| if !bigToBn(&key.n, N) || |
| !bigToBn(&key.e, E) { |
| return nil, fail("BN_bin2bn") |
| } |
| k := &PublicKeyRSA{key: key} |
| // Note: Because of the finalizer, any time k.key is passed to cgo, |
| // that call must be followed by a call to runtime.KeepAlive(k), |
| // to make sure k is not collected (and finalized) before the cgo |
| // call returns. |
| runtime.SetFinalizer(k, (*PublicKeyRSA).finalize) |
| return k, nil |
| } |
| |
| func (k *PublicKeyRSA) finalize() { |
| C._goboringcrypto_RSA_free(k.key) |
| } |
| |
| type PrivateKeyRSA struct { |
| key *C.GO_RSA |
| } |
| |
| func NewPrivateKeyRSA(N, E, D, P, Q, Dp, Dq, Qinv *big.Int) (*PrivateKeyRSA, error) { |
| key := C._goboringcrypto_RSA_new() |
| if key == nil { |
| return nil, fail("RSA_new") |
| } |
| if !bigToBn(&key.n, N) || |
| !bigToBn(&key.e, E) || |
| !bigToBn(&key.d, D) || |
| !bigToBn(&key.p, P) || |
| !bigToBn(&key.q, Q) || |
| !bigToBn(&key.dmp1, Dp) || |
| !bigToBn(&key.dmq1, Dq) || |
| !bigToBn(&key.iqmp, Qinv) { |
| return nil, fail("BN_bin2bn") |
| } |
| k := &PrivateKeyRSA{key: key} |
| // Note: Because of the finalizer, any time k.key is passed to cgo, |
| // that call must be followed by a call to runtime.KeepAlive(k), |
| // to make sure k is not collected (and finalized) before the cgo |
| // call returns. |
| runtime.SetFinalizer(k, (*PrivateKeyRSA).finalize) |
| return k, nil |
| } |
| |
| func (k *PrivateKeyRSA) finalize() { |
| C._goboringcrypto_RSA_free(k.key) |
| } |
| |
| func setupRSA(key *C.GO_RSA, |
| padding C.int, h hash.Hash, label []byte, saltLen int, ch crypto.Hash, |
| init func(*C.GO_EVP_PKEY_CTX) C.int) (pkey *C.GO_EVP_PKEY, ctx *C.GO_EVP_PKEY_CTX, err error) { |
| defer func() { |
| if err != nil { |
| if pkey != nil { |
| C._goboringcrypto_EVP_PKEY_free(pkey) |
| pkey = nil |
| } |
| if ctx != nil { |
| C._goboringcrypto_EVP_PKEY_CTX_free(ctx) |
| ctx = nil |
| } |
| } |
| }() |
| |
| pkey = C._goboringcrypto_EVP_PKEY_new() |
| if pkey == nil { |
| return nil, nil, fail("EVP_PKEY_new") |
| } |
| if C._goboringcrypto_EVP_PKEY_set1_RSA(pkey, key) == 0 { |
| return nil, nil, fail("EVP_PKEY_set1_RSA") |
| } |
| ctx = C._goboringcrypto_EVP_PKEY_CTX_new(pkey, nil) |
| if ctx == nil { |
| return nil, nil, fail("EVP_PKEY_CTX_new") |
| } |
| if init(ctx) == 0 { |
| return nil, nil, fail("EVP_PKEY_operation_init") |
| } |
| if C._goboringcrypto_EVP_PKEY_CTX_set_rsa_padding(ctx, padding) == 0 { |
| return nil, nil, fail("EVP_PKEY_CTX_set_rsa_padding") |
| } |
| if padding == C.GO_RSA_PKCS1_OAEP_PADDING { |
| md := hashToMD(h) |
| if md == nil { |
| return nil, nil, errors.New("crypto/rsa: unsupported hash function") |
| } |
| if C._goboringcrypto_EVP_PKEY_CTX_set_rsa_oaep_md(ctx, md) == 0 { |
| return nil, nil, fail("EVP_PKEY_set_rsa_oaep_md") |
| } |
| // ctx takes ownership of label, so malloc a copy for BoringCrypto to free. |
| clabel := (*C.uint8_t)(C.malloc(C.size_t(len(label)))) |
| if clabel == nil { |
| return nil, nil, fail("malloc") |
| } |
| copy((*[1 << 30]byte)(unsafe.Pointer(clabel))[:len(label)], label) |
| if C._goboringcrypto_EVP_PKEY_CTX_set0_rsa_oaep_label(ctx, clabel, C.size_t(len(label))) == 0 { |
| return nil, nil, fail("EVP_PKEY_CTX_set0_rsa_oaep_label") |
| } |
| } |
| if padding == C.GO_RSA_PKCS1_PSS_PADDING { |
| if saltLen != 0 { |
| if C._goboringcrypto_EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, C.int(saltLen)) == 0 { |
| return nil, nil, fail("EVP_PKEY_set_rsa_pss_saltlen") |
| } |
| } |
| md := cryptoHashToMD(ch) |
| if md == nil { |
| return nil, nil, errors.New("crypto/rsa: unsupported hash function") |
| } |
| if C._goboringcrypto_EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, md) == 0 { |
| return nil, nil, fail("EVP_PKEY_set_rsa_mgf1_md") |
| } |
| } |
| |
| return pkey, ctx, nil |
| } |
| |
| func cryptRSA(gokey interface{}, key *C.GO_RSA, |
| padding C.int, h hash.Hash, label []byte, saltLen int, ch crypto.Hash, |
| init func(*C.GO_EVP_PKEY_CTX) C.int, |
| crypt func(*C.GO_EVP_PKEY_CTX, *C.uint8_t, *C.size_t, *C.uint8_t, C.size_t) C.int, |
| in []byte) ([]byte, error) { |
| |
| pkey, ctx, err := setupRSA(key, padding, h, label, saltLen, ch, init) |
| if err != nil { |
| return nil, err |
| } |
| defer C._goboringcrypto_EVP_PKEY_free(pkey) |
| defer C._goboringcrypto_EVP_PKEY_CTX_free(ctx) |
| |
| var outLen C.size_t |
| if crypt(ctx, nil, &outLen, base(in), C.size_t(len(in))) == 0 { |
| return nil, fail("EVP_PKEY_decrypt/encrypt") |
| } |
| out := make([]byte, outLen) |
| if crypt(ctx, base(out), &outLen, base(in), C.size_t(len(in))) == 0 { |
| return nil, fail("EVP_PKEY_decrypt/encrypt") |
| } |
| runtime.KeepAlive(gokey) // keep key from being freed before now |
| return out[:outLen], nil |
| } |
| |
| func DecryptRSAOAEP(h hash.Hash, priv *PrivateKeyRSA, ciphertext, label []byte) ([]byte, error) { |
| return cryptRSA(priv, priv.key, C.GO_RSA_PKCS1_OAEP_PADDING, h, label, 0, 0, decryptInit, decrypt, ciphertext) |
| } |
| |
| func EncryptRSAOAEP(h hash.Hash, pub *PublicKeyRSA, msg, label []byte) ([]byte, error) { |
| return cryptRSA(pub, pub.key, C.GO_RSA_PKCS1_OAEP_PADDING, h, label, 0, 0, encryptInit, encrypt, msg) |
| } |
| |
| func DecryptRSAPKCS1(priv *PrivateKeyRSA, ciphertext []byte) ([]byte, error) { |
| return cryptRSA(priv, priv.key, C.GO_RSA_PKCS1_PADDING, nil, nil, 0, 0, decryptInit, decrypt, ciphertext) |
| } |
| |
| func EncryptRSAPKCS1(pub *PublicKeyRSA, msg []byte) ([]byte, error) { |
| return cryptRSA(pub, pub.key, C.GO_RSA_PKCS1_PADDING, nil, nil, 0, 0, encryptInit, encrypt, msg) |
| } |
| |
| func DecryptRSANoPadding(priv *PrivateKeyRSA, ciphertext []byte) ([]byte, error) { |
| return cryptRSA(priv, priv.key, C.GO_RSA_NO_PADDING, nil, nil, 0, 0, decryptInit, decrypt, ciphertext) |
| } |
| |
| func EncryptRSANoPadding(pub *PublicKeyRSA, msg []byte) ([]byte, error) { |
| return cryptRSA(pub, pub.key, C.GO_RSA_NO_PADDING, nil, nil, 0, 0, encryptInit, encrypt, msg) |
| } |
| |
| // These dumb wrappers work around the fact that cgo functions cannot be used as values directly. |
| |
| func decryptInit(ctx *C.GO_EVP_PKEY_CTX) C.int { |
| return C._goboringcrypto_EVP_PKEY_decrypt_init(ctx) |
| } |
| |
| func decrypt(ctx *C.GO_EVP_PKEY_CTX, out *C.uint8_t, outLen *C.size_t, in *C.uint8_t, inLen C.size_t) C.int { |
| return C._goboringcrypto_EVP_PKEY_decrypt(ctx, out, outLen, in, inLen) |
| } |
| |
| func encryptInit(ctx *C.GO_EVP_PKEY_CTX) C.int { |
| return C._goboringcrypto_EVP_PKEY_encrypt_init(ctx) |
| } |
| |
| func encrypt(ctx *C.GO_EVP_PKEY_CTX, out *C.uint8_t, outLen *C.size_t, in *C.uint8_t, inLen C.size_t) C.int { |
| return C._goboringcrypto_EVP_PKEY_encrypt(ctx, out, outLen, in, inLen) |
| } |
| |
| func SignRSAPSS(priv *PrivateKeyRSA, h crypto.Hash, hashed []byte, saltLen int) ([]byte, error) { |
| md := cryptoHashToMD(h) |
| if md == nil { |
| return nil, errors.New("crypto/rsa: unsupported hash function") |
| } |
| if saltLen == 0 { |
| saltLen = -1 |
| } |
| out := make([]byte, C._goboringcrypto_RSA_size(priv.key)) |
| var outLen C.size_t |
| if C._goboringcrypto_RSA_sign_pss_mgf1(priv.key, &outLen, base(out), C.size_t(len(out)), base(hashed), C.size_t(len(hashed)), md, nil, C.int(saltLen)) == 0 { |
| return nil, fail("RSA_sign_pss_mgf1") |
| } |
| runtime.KeepAlive(priv) |
| |
| return out[:outLen], nil |
| } |
| |
| func VerifyRSAPSS(pub *PublicKeyRSA, h crypto.Hash, hashed, sig []byte, saltLen int) error { |
| md := cryptoHashToMD(h) |
| if md == nil { |
| return errors.New("crypto/rsa: unsupported hash function") |
| } |
| if saltLen == 0 { |
| saltLen = -2 // auto-recover |
| } |
| if C._goboringcrypto_RSA_verify_pss_mgf1(pub.key, base(hashed), C.size_t(len(hashed)), md, nil, C.int(saltLen), base(sig), C.size_t(len(sig))) == 0 { |
| return fail("RSA_verify_pss_mgf1") |
| } |
| runtime.KeepAlive(pub) |
| return nil |
| } |
| |
| func SignRSAPKCS1v15(priv *PrivateKeyRSA, h crypto.Hash, hashed []byte) ([]byte, error) { |
| out := make([]byte, C._goboringcrypto_RSA_size(priv.key)) |
| if h == 0 { |
| // No hashing. |
| var outLen C.size_t |
| if C._goboringcrypto_RSA_sign_raw(priv.key, &outLen, base(out), C.size_t(len(out)), base(hashed), C.size_t(len(hashed)), C.GO_RSA_PKCS1_PADDING) == 0 { |
| return nil, fail("RSA_sign_raw") |
| } |
| runtime.KeepAlive(priv) |
| return out[:outLen], nil |
| } |
| |
| md := cryptoHashToMD(h) |
| if md == nil { |
| return nil, errors.New("crypto/rsa: unsupported hash function: " + strconv.Itoa(int(h))) |
| } |
| nid := C._goboringcrypto_EVP_MD_type(md) |
| var outLen C.uint |
| if C._goboringcrypto_RSA_sign(nid, base(hashed), C.uint(len(hashed)), base(out), &outLen, priv.key) == 0 { |
| return nil, fail("RSA_sign") |
| } |
| runtime.KeepAlive(priv) |
| return out[:outLen], nil |
| } |
| |
| func VerifyRSAPKCS1v15(pub *PublicKeyRSA, h crypto.Hash, hashed, sig []byte) error { |
| size := int(C._goboringcrypto_RSA_size(pub.key)) |
| if len(sig) < size { |
| // BoringCrypto requires sig to be same size as RSA key, so pad with leading zeros. |
| zsig := make([]byte, size) |
| copy(zsig[len(zsig)-len(sig):], sig) |
| sig = zsig |
| } |
| if h == 0 { |
| var outLen C.size_t |
| out := make([]byte, size) |
| if C._goboringcrypto_RSA_verify_raw(pub.key, &outLen, base(out), C.size_t(len(out)), base(sig), C.size_t(len(sig)), C.GO_RSA_PKCS1_PADDING) == 0 { |
| return fail("RSA_verify") |
| } |
| if subtle.ConstantTimeCompare(hashed, out[:outLen]) != 1 { |
| return fail("RSA_verify") |
| } |
| runtime.KeepAlive(pub) |
| return nil |
| } |
| md := cryptoHashToMD(h) |
| if md == nil { |
| return errors.New("crypto/rsa: unsupported hash function") |
| } |
| nid := C._goboringcrypto_EVP_MD_type(md) |
| if C._goboringcrypto_RSA_verify(nid, base(hashed), C.size_t(len(hashed)), base(sig), C.size_t(len(sig)), pub.key) == 0 { |
| return fail("RSA_verify") |
| } |
| runtime.KeepAlive(pub) |
| return nil |
| } |