- Notifications
You must be signed in to change notification settings - Fork 18.5k
Closed as duplicate of#65716
Closed as duplicate of#65716
Copy link
Labels
LibraryProposalIssues describing a requested change to the Go standard library or x/ libraries, but not to a toolIssues describing a requested change to the Go standard library or x/ libraries, but not to a toolProposalProposal-CryptoProposal related to crypto packages or other security issuesProposal related to crypto packages or other security issues
Milestone
Description
Proposal Details
Hello, everyone.
Currently, I've encountered an issue where the RSA encryption algorithms are inconsistent across different languages during the project integration process. To address this problem, I had no choice but to modify some code in the crypto basic library.
Process:
- When integrating with a Java implementation of the RSA encryption program, it can be found that the Java implementation uses the
RSA/ECB/OAEPWithSHA-256AndMGF1Paddingmethod. - When I used the private key for decryption, I found that the
DecryptOAEPmethod incryptoonly provides a single input parameter for theHashalgorithm. When I usedsha256.New()to create the hash, the lack ofMGF1Paddingcaused the decryption to fail.
Code:
func DecryptOAEP(hash hash.Hash, random io.Reader, priv *PrivateKey, ciphertext []byte, label []byte) ([]byte, error) { // hash, hash reuse common Hash return decryptOAEP(hash, hash, random, priv, ciphertext, label) } - Later, I discovered that
PrivateKeyprovides aDecryptmethod, which can be implemented through the extensibleopts crypto.DecrypterOpts, thus solving my problem.
func (priv *PrivateKey) Decrypt(rand io.Reader, ciphertext []byte, opts crypto.DecrypterOpts) (plaintext []byte, err error) { if opts == nil { return DecryptPKCS1v15(rand, priv, ciphertext) } switch opts := opts.(type) { case *OAEPOptions: if opts.MGFHash == 0 { return decryptOAEP(opts.Hash.New(), opts.Hash.New(), rand, priv, ciphertext, opts.Label) } else { return decryptOAEP(opts.Hash.New(), opts.MGFHash.New(), rand, priv, ciphertext, opts.Label) } case *PKCS1v15DecryptOptions: if l := opts.SessionKeyLen; l > 0 { plaintext = make([]byte, l) if _, err := io.ReadFull(rand, plaintext); err != nil { return nil, err } if err := DecryptPKCS1v15SessionKey(rand, priv, ciphertext, plaintext); err != nil { return nil, err } return plaintext, nil } else { return DecryptPKCS1v15(rand, priv, ciphertext) } default: return nil, errors.New("crypto/rsa: invalid options for Decrypt") } }- Originally, I thought I was just one step away from success. However, here comes the problem when I implemented the Golang encryption. During decryption, we used two hash algorithms as factors for decryption to implement
RSA/ECB/OAEPWithSHA-256AndMGF1Padding, and the official also provides standard APIs. - During encryption, there should be a similar interface to support
RSA/ECB/OAEPWithSHA-256AndMGF1Padding. Unfortunately, I couldn't find such a method.
Optimization suggestion:
Can you geniuses provide an external interface that exposes a method similar to func (priv *PrivateKey) Decrypt(rand io.Reader, ciphertext []byte, opts crypto.DecrypterOpts) (plaintext []byte, err error)?
The following is the code I used to solve my problem. I hope it can be of some help. Of course, there is still much room for improvement.
type EncrypterOpts any func (pub *PublicKey) Encrypt(rand io.Reader, msg []byte, opts EncrypterOpts) (plaintext []byte, err error) { if opts == nil { return EncryptPKCS1v15(rand, pub, msg) } switch opts := opts.(type) { case *OAEPOptions: if opts.MGFHash == 0 { return encryptOAEP(opts.Hash.New(), opts.Hash.New(), rand, pub, msg, opts.Label) } else { return encryptOAEP(opts.Hash.New(), opts.MGFHash.New(), rand, pub, msg, opts.Label) } default: return nil, errors.New("crypto/rsa: invalid options for Encrypt") } } func encryptOAEP(hash, MGFHash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, label []byte) ([]byte, error) { // Note that while we don't commit to deterministic execution with respect // to the random stream, we also don't apply MaybeReadByte, so per Hyrum's // Law it's probably relied upon by some. It's a tolerable promise because a // well-specified number of random bytes is included in the ciphertext, in a // well-specified way. if err := checkPub(pub); err != nil { return nil, err } hash.Reset() k := pub.Size() if len(msg) > k-2*hash.Size()-2 { return nil, ErrMessageTooLong } hash.Write(label) lHash := hash.Sum(nil) hash.Reset() em := make([]byte, k) seed := em[1 : 1+hash.Size()] db := em[1+hash.Size():] copy(db[0:hash.Size()], lHash) db[len(db)-len(msg)-1] = 1 copy(db[len(db)-len(msg):], msg) _, err := io.ReadFull(random, seed) if err != nil { return nil, err } mgf1XOR(db, MGFHash, seed) mgf1XOR(seed, MGFHash, db) return encrypt(pub, em) }I'm looking forward to your replies.
Metadata
Metadata
Assignees
Labels
LibraryProposalIssues describing a requested change to the Go standard library or x/ libraries, but not to a toolIssues describing a requested change to the Go standard library or x/ libraries, but not to a toolProposalProposal-CryptoProposal related to crypto packages or other security issuesProposal related to crypto packages or other security issues
Type
Projects
Status
Incoming