Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 23 additions & 5 deletions xcrypto/rsa.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ package xcrypto
// #include <Security/Security.h>
import "C"
import (
"bytes"
"crypto"
"errors"
"hash"
Expand Down Expand Up @@ -101,18 +102,35 @@ func (k *PrivateKeyRSA) withKey(f func(C.SecKeyRef) C.int) C.int {

// DecryptRSAOAEP decrypts data using RSA-OAEP.
func DecryptRSAOAEP(h hash.Hash, priv *PrivateKeyRSA, ciphertext, label []byte) ([]byte, error) {
plaintext, err := evpDecrypt(priv.withKey, algorithmTypeOAEP, ciphertext, h)
if err != nil {
return nil, err
}
// If a label was provided, validate it
if len(label) > 0 {
// https://github.com/microsoft/go-crypto-darwin/issues/22
panic("crypto/rsa: label is not supported on macOS")
h.Write(label)
labelHash := h.Sum(nil)
h.Reset()
if len(plaintext) < len(labelHash) {
return nil, errors.New("invalid ciphertext: missing label hash")
}
// Extract and verify the label hash
if !bytes.Equal(plaintext[:len(labelHash)], labelHash) {
return nil, errors.New("invalid label hash")
}
Comment on lines +114 to +120
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Almost) never use bytes.Equal in crypto code, as it is vulnerable to oracle side channel attacks. Use suble.ConstantTimeCompare. Also, don't short-circuit if the length are not equal, for the same reason.

plaintext = plaintext[len(labelHash):]
}
return evpDecrypt(priv.withKey, algorithmTypeOAEP, ciphertext, h)
return plaintext, nil
}

// EncryptRSAOAEP encrypts data using RSA-OAEP.
func EncryptRSAOAEP(h hash.Hash, pub *PublicKeyRSA, msg, label []byte) ([]byte, error) {
// Combine label with plaintext for encryption
if len(label) > 0 {
// https://github.com/microsoft/go-crypto-darwin/issues/22
panic("crypto/rsa: label is not supported on macOS")
h.Write(label)
labelHash := h.Sum(nil)
msg = append(labelHash, msg...) // Prepend label hash to the message
h.Reset()
}
return evpEncrypt(pub.withKey, algorithmTypeOAEP, msg, h)
}
Expand Down
3 changes: 1 addition & 2 deletions xcrypto/rsa_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func TestRSAEncryptDecryptPKCS1(t *testing.T) {
func TestRSAEncryptDecryptOAEP(t *testing.T) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test that upstream crypto/rsa can decrypt ciphertexts (with labels) generated by us and vice-versa.

sha256 := xcrypto.NewSHA256()
msg := []byte("hi!")
label := []byte("") // Set label to empty as CommonCrypto does not support custom label
label := []byte("ho!")
priv, pub := newRSAKey(t, 2048)
enc, err := xcrypto.EncryptRSAOAEP(sha256, pub, msg, label)
if err != nil {
Expand Down Expand Up @@ -102,7 +102,6 @@ func TestRSAEncryptDecryptOAEP_EmptyLabel(t *testing.T) {
}

func TestRSAEncryptDecryptOAEP_WrongLabel(t *testing.T) {
t.Skip("Skipping test as CommonCrypto does not support custom label")
sha256 := xcrypto.NewSHA256()
msg := []byte("hi!")
priv, pub := newRSAKey(t, 2048)
Expand Down
Loading