Skip to content
This repository was archived by the owner on Oct 19, 2024. It is now read-only.

Commit c6f7932

Browse files
lcforgesericchiang
authored andcommitted
feat: add support for decryption
1 parent 3bb1db4 commit c6f7932

File tree

2 files changed

+186
-28
lines changed

2 files changed

+186
-28
lines changed

pkcs11/pkcs11.go

Lines changed: 111 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,26 @@ CK_RV ck_sign(
232232
) {
233233
return (*fl->C_Sign)(hSession, pData, ulDataLen, pSignature, pulSignatureLen);
234234
}
235+
236+
CK_RV ck_decrypt_init(
237+
CK_FUNCTION_LIST_PTR fl,
238+
CK_SESSION_HANDLE hSession,
239+
CK_MECHANISM_PTR pMechanism,
240+
CK_OBJECT_HANDLE hKey
241+
) {
242+
return (*fl->C_DecryptInit)(hSession, pMechanism, hKey);
243+
}
244+
245+
CK_RV ck_decrypt(
246+
CK_FUNCTION_LIST_PTR fl,
247+
CK_SESSION_HANDLE hSession,
248+
CK_BYTE_PTR pEncryptedData,
249+
CK_ULONG ulEncryptedDataLen,
250+
CK_BYTE_PTR pData,
251+
CK_ULONG_PTR pulDataLen
252+
) {
253+
return (*fl->C_Decrypt)(hSession, pEncryptedData, ulEncryptedDataLen, pData, pulDataLen);
254+
}
235255
*/
236256
// #cgo linux LDFLAGS: -ldl
237257
import "C"
@@ -1226,20 +1246,15 @@ func (r *rsaPrivateKey) Sign(_ io.Reader, digest []byte, opts crypto.SignerOpts)
12261246
// http://docs.oasis-open.org/pkcs11/pkcs11-curr/v2.40/cs01/pkcs11-curr-v2.40-cs01.html#_Toc399398842
12271247
size := opts.HashFunc().Size()
12281248
if size != len(digest) {
1229-
return nil, fmt.Errorf("input mush be hashed")
1249+
return nil, fmt.Errorf("input must be hashed")
12301250
}
12311251
prefix, ok := hashPrefixes[opts.HashFunc()]
12321252
if !ok {
12331253
return nil, fmt.Errorf("unsupported hash function: %s", opts.HashFunc())
12341254
}
12351255

1236-
cBytes := make([]C.CK_BYTE, len(prefix)+len(digest))
1237-
for i, b := range prefix {
1238-
cBytes[i] = C.CK_BYTE(b)
1239-
}
1240-
for i, b := range digest {
1241-
cBytes[len(prefix)+i] = C.CK_BYTE(b)
1242-
}
1256+
preAndDigest := append(prefix, digest...)
1257+
cBytes := toCBytes(preAndDigest)
12431258

12441259
cSig := make([]C.CK_BYTE, r.pub.Size())
12451260
cSigLen := C.CK_ULONG(len(cSig))
@@ -1257,10 +1272,7 @@ func (r *rsaPrivateKey) Sign(_ io.Reader, digest []byte, opts crypto.SignerOpts)
12571272
if int(cSigLen) != len(cSig) {
12581273
return nil, fmt.Errorf("expected signature of length %d, got %d", len(cSig), cSigLen)
12591274
}
1260-
sig := make([]byte, len(cSig))
1261-
for i, b := range cSig {
1262-
sig[i] = byte(b)
1263-
}
1275+
sig := toBytes(cSig)
12641276
return sig, nil
12651277
}
12661278

@@ -1295,10 +1307,7 @@ func (r *rsaPrivateKey) signPSS(digest []byte, opts *rsa.PSSOptions) ([]byte, er
12951307
cParam.sLen = C.CK_ULONG(opts.SaltLength)
12961308
}
12971309

1298-
cBytes := make([]C.CK_BYTE, len(digest))
1299-
for i, b := range digest {
1300-
cBytes[i] = C.CK_BYTE(b)
1301-
}
1310+
cBytes := toCBytes(digest)
13021311

13031312
cSig := make([]C.CK_BYTE, r.pub.Size())
13041313
cSigLen := C.CK_ULONG(len(cSig))
@@ -1321,10 +1330,7 @@ func (r *rsaPrivateKey) signPSS(digest []byte, opts *rsa.PSSOptions) ([]byte, er
13211330
if int(cSigLen) != len(cSig) {
13221331
return nil, fmt.Errorf("expected signature of length %d, got %d", len(cSig), cSigLen)
13231332
}
1324-
sig := make([]byte, len(cSig))
1325-
for i, b := range cSig {
1326-
sig[i] = byte(b)
1327-
}
1333+
sig := toBytes(cSig)
13281334
return sig, nil
13291335
}
13301336

@@ -1353,10 +1359,7 @@ func (e *ecdsaPrivateKey) Sign(_ io.Reader, digest []byte, opts crypto.SignerOpt
13531359
cSig := make([]C.CK_BYTE, byteLen*2)
13541360
cSigLen := C.CK_ULONG(len(cSig))
13551361

1356-
cBytes := make([]C.CK_BYTE, len(digest))
1357-
for i, b := range digest {
1358-
cBytes[i] = C.CK_BYTE(b)
1359-
}
1362+
cBytes := toCBytes(digest)
13601363

13611364
rv = C.ck_sign(e.o.fl, e.o.h, &cBytes[0], C.CK_ULONG(len(digest)), &cSig[0], &cSigLen)
13621365
if err := isOk("C_Sign", rv); err != nil {
@@ -1366,10 +1369,7 @@ func (e *ecdsaPrivateKey) Sign(_ io.Reader, digest []byte, opts crypto.SignerOpt
13661369
if int(cSigLen) != len(cSig) {
13671370
return nil, fmt.Errorf("expected signature of length %d, got %d", len(cSig), cSigLen)
13681371
}
1369-
sig := make([]byte, len(cSig))
1370-
for i, b := range cSig {
1371-
sig[i] = byte(b)
1372-
}
1372+
sig := toBytes(cSig)
13731373

13741374
var (
13751375
r = big.NewInt(0)
@@ -1687,3 +1687,86 @@ func (s *Slot) generateECDSA(o keyOptions) (crypto.PrivateKey, error) {
16871687
}
16881688
return priv, nil
16891689
}
1690+
1691+
func (r *rsaPrivateKey) Decrypt(_ io.Reader, encryptedData []byte, opts crypto.DecrypterOpts) ([]byte, error) {
1692+
var m C.CK_MECHANISM
1693+
1694+
if o, ok := opts.(*rsa.OAEPOptions); ok {
1695+
cParam := (C.CK_RSA_PKCS_OAEP_PARAMS_PTR)(C.malloc(C.sizeof_CK_RSA_PKCS_OAEP_PARAMS))
1696+
defer C.free(unsafe.Pointer(cParam))
1697+
1698+
switch o.Hash {
1699+
case crypto.SHA256:
1700+
cParam.hashAlg = C.CKM_SHA256
1701+
cParam.mgf = C.CKG_MGF1_SHA256
1702+
case crypto.SHA384:
1703+
cParam.hashAlg = C.CKM_SHA384
1704+
cParam.mgf = C.CKG_MGF1_SHA384
1705+
case crypto.SHA512:
1706+
cParam.hashAlg = C.CKM_SHA512
1707+
cParam.mgf = C.CKG_MGF1_SHA512
1708+
case crypto.SHA1:
1709+
cParam.hashAlg = C.CKM_SHA_1
1710+
cParam.mgf = C.CKG_MGF1_SHA1
1711+
default:
1712+
return nil, fmt.Errorf("decryptOAEP error, unsupported hash algorithm: %s", o.Hash)
1713+
}
1714+
1715+
cParam.source = C.CKZ_DATA_SPECIFIED
1716+
cParam.pSourceData = nil
1717+
cParam.ulSourceDataLen = 0
1718+
1719+
m = C.CK_MECHANISM{
1720+
mechanism: C.CKM_RSA_PKCS_OAEP,
1721+
pParameter: C.CK_VOID_PTR(cParam),
1722+
ulParameterLen: C.CK_ULONG(C.sizeof_CK_RSA_PKCS_OAEP_PARAMS),
1723+
}
1724+
} else {
1725+
m = C.CK_MECHANISM{C.CKM_RSA_PKCS, nil, 0}
1726+
}
1727+
1728+
cEncDataBytes := toCBytes(encryptedData)
1729+
1730+
rv := C.ck_decrypt_init(r.o.fl, r.o.h, &m, r.o.o)
1731+
if err := isOk("C_DecryptInit", rv); err != nil {
1732+
return nil, err
1733+
}
1734+
1735+
var cDecryptedLen C.CK_ULONG
1736+
1737+
// First call is used to determine length necessary to hold decrypted data (PKCS #11 5.2)
1738+
rv = C.ck_decrypt(r.o.fl, r.o.h, &cEncDataBytes[0], C.CK_ULONG(len(cEncDataBytes)), nil, &cDecryptedLen)
1739+
if err := isOk("C_Decrypt", rv); err != nil {
1740+
return nil, err
1741+
}
1742+
1743+
cDecrypted := make([]C.CK_BYTE, cDecryptedLen)
1744+
1745+
rv = C.ck_decrypt(r.o.fl, r.o.h, &cEncDataBytes[0], C.CK_ULONG(len(cEncDataBytes)), &cDecrypted[0], &cDecryptedLen)
1746+
if err := isOk("C_Decrypt", rv); err != nil {
1747+
return nil, err
1748+
}
1749+
1750+
decrypted := toBytes(cDecrypted)
1751+
1752+
// Removes null padding (PKCS#11 5.2): http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/os/pkcs11-base-v2.40-os.html#_Toc416959738
1753+
decrypted = bytes.Trim(decrypted, "\x00")
1754+
1755+
return decrypted, nil
1756+
}
1757+
1758+
func toBytes(data []C.CK_BYTE) []byte {
1759+
goBytes := make([]byte, len(data))
1760+
for i, b := range data {
1761+
goBytes[i] = byte(b)
1762+
}
1763+
return goBytes
1764+
}
1765+
1766+
func toCBytes(data []byte) []C.CK_BYTE {
1767+
cBytes := make([]C.CK_BYTE, len(data))
1768+
for i, b := range data {
1769+
cBytes[i] = C.CK_BYTE(b)
1770+
}
1771+
return cBytes
1772+
}

pkcs11/pkcs11_test.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"crypto/elliptic"
2222
"crypto/rand"
2323
"crypto/rsa"
24+
"crypto/sha1"
2425
"crypto/sha256"
2526
"crypto/x509"
2627
"encoding/pem"
@@ -594,3 +595,77 @@ func TestCreateCertificate(t *testing.T) {
594595
t.Errorf("Returned certificate did not match loaded certificate")
595596
}
596597
}
598+
599+
func TestDecryptOAEP(t *testing.T) {
600+
msg := "Plain text to encrypt"
601+
b := []byte(msg)
602+
tests := []struct {
603+
name string
604+
bits int
605+
}{
606+
{"2048", 2048},
607+
{"4096", 4096},
608+
}
609+
for _, test := range tests {
610+
t.Run(test.name, func(t *testing.T) {
611+
s := newTestSlot(t)
612+
o := keyOptions{RSABits: test.bits}
613+
priv, err := s.generate(o)
614+
if err != nil {
615+
t.Fatalf("generate(%#v) failed: %v", o, err)
616+
}
617+
rsaPub := priv.(*rsaPrivateKey).pub
618+
// SHA1 is the only hash function supported by softhsm
619+
cipher, err := rsa.EncryptOAEP(sha1.New(), rand.Reader, rsaPub, b, nil)
620+
if err != nil {
621+
t.Fatalf("EncryptOAEP Error: %v", err)
622+
}
623+
opts := &rsa.OAEPOptions{Hash: crypto.SHA1}
624+
rsaDecrypter := priv.(crypto.Decrypter)
625+
decrypted, err := rsaDecrypter.Decrypt(nil, cipher, opts)
626+
if err != nil {
627+
t.Fatalf("Decrypt Error: %v", err)
628+
}
629+
if string(decrypted) != msg {
630+
t.Errorf("Decrypt Error: expected %q, got %q", msg, string(decrypted))
631+
}
632+
})
633+
}
634+
}
635+
636+
func TestDecryptPKCS(t *testing.T) {
637+
msg := "Plain text to encrypt"
638+
b := []byte(msg)
639+
tests := []struct {
640+
name string
641+
bits int
642+
}{
643+
{"2048", 2048},
644+
{"4096", 4096},
645+
}
646+
for _, test := range tests {
647+
t.Run(test.name, func(t *testing.T) {
648+
s := newTestSlot(t)
649+
o := keyOptions{RSABits: test.bits}
650+
priv, err := s.generate(o)
651+
if err != nil {
652+
t.Fatalf("generate(%#v) failed: %v", o, err)
653+
}
654+
rsaPub := priv.(*rsaPrivateKey).pub
655+
cipher, err := rsa.EncryptPKCS1v15(rand.Reader, rsaPub, b)
656+
if err != nil {
657+
t.Fatalf("EncryptPKCS1v15 Error: %v", err)
658+
}
659+
rsaDecrypter := priv.(crypto.Decrypter)
660+
661+
// nil opts for decrypting using PKCS #1 v 1.5
662+
decrypted, err := rsaDecrypter.Decrypt(nil, cipher, nil)
663+
if err != nil {
664+
t.Fatalf("Decrypt Error: %v", err)
665+
}
666+
if string(decrypted) != msg {
667+
t.Errorf("Decrypt Error: expected %q, got %q", msg, string(decrypted))
668+
}
669+
})
670+
}
671+
}

0 commit comments

Comments
 (0)