| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162 |
- package xmlenc
- import (
- "crypto/rsa"
- "crypto/x509"
- "encoding/base64"
- "fmt"
- "github.com/beevik/etree"
- )
- // RSA implements Encrypter and Decrypter using RSA public key encryption.
- //
- // Use function like OAEP(), or PKCS1v15() to get an instance of this type ready
- // to use.
- type RSA struct {
- BlockCipher BlockCipher
- DigestMethod DigestMethod // only for OAEP
- algorithm string
- keyEncrypter func(e RSA, pubKey *rsa.PublicKey, plaintext []byte) ([]byte, error)
- keyDecrypter func(e RSA, privKey *rsa.PrivateKey, ciphertext []byte) ([]byte, error)
- }
- // Algorithm returns the name of the algorithm
- func (e RSA) Algorithm() string {
- return e.algorithm
- }
- // Encrypt implements encrypter. certificate must be a []byte containing the ASN.1 bytes
- // of certificate containing an RSA public key.
- func (e RSA) Encrypt(certificate interface{}, plaintext []byte) (*etree.Element, error) {
- cert, ok := certificate.(*x509.Certificate)
- if !ok {
- return nil, ErrIncorrectKeyType("*x.509 certificate")
- }
- pubKey, ok := cert.PublicKey.(*rsa.PublicKey)
- if !ok {
- return nil, ErrIncorrectKeyType("x.509 certificate with an RSA public key")
- }
- // generate a key
- key := make([]byte, e.BlockCipher.KeySize())
- if _, err := RandReader.Read(key); err != nil {
- return nil, err
- }
- keyInfoEl := etree.NewElement("ds:KeyInfo")
- keyInfoEl.CreateAttr("xmlns:ds", "http://www.w3.org/2000/09/xmldsig#")
- encryptedKey := keyInfoEl.CreateElement("xenc:EncryptedKey")
- {
- randBuf := make([]byte, 16)
- if _, err := RandReader.Read(randBuf); err != nil {
- return nil, err
- }
- encryptedKey.CreateAttr("Id", fmt.Sprintf("_%x", randBuf))
- }
- encryptedKey.CreateAttr("xmlns:xenc", "http://www.w3.org/2001/04/xmlenc#")
- encryptionMethodEl := encryptedKey.CreateElement("xenc:EncryptionMethod")
- encryptionMethodEl.CreateAttr("Algorithm", e.algorithm)
- encryptionMethodEl.CreateAttr("xmlns:xenc", "http://www.w3.org/2001/04/xmlenc#")
- if e.DigestMethod != nil {
- dm := encryptionMethodEl.CreateElement("ds:DigestMethod")
- dm.CreateAttr("Algorithm", e.DigestMethod.Algorithm())
- dm.CreateAttr("xmlns:ds", "http://www.w3.org/2000/09/xmldsig#")
- }
- {
- innerKeyInfoEl := encryptedKey.CreateElement("ds:KeyInfo")
- x509data := innerKeyInfoEl.CreateElement("ds:X509Data")
- x509data.CreateElement("ds:X509Certificate").SetText(
- base64.StdEncoding.EncodeToString(cert.Raw),
- )
- }
- buf, err := e.keyEncrypter(e, pubKey, key)
- if err != nil {
- return nil, err
- }
- cd := encryptedKey.CreateElement("xenc:CipherData")
- cd.CreateAttr("xmlns:xenc", "http://www.w3.org/2001/04/xmlenc#")
- cd.CreateElement("xenc:CipherValue").SetText(base64.StdEncoding.EncodeToString(buf))
- encryptedDataEl, err := e.BlockCipher.Encrypt(key, plaintext)
- if err != nil {
- return nil, err
- }
- encryptedDataEl.InsertChild(encryptedDataEl.FindElement("./CipherData"), keyInfoEl)
- return encryptedDataEl, nil
- }
- // Decrypt implements Decryptor. `key` must be an *rsa.PrivateKey.
- func (e RSA) Decrypt(key interface{}, ciphertextEl *etree.Element) ([]byte, error) {
- rsaKey, err := validateRSAKey(key, ciphertextEl)
- if err != nil {
- return nil, err
- }
- ciphertext, err := getCiphertext(ciphertextEl)
- if err != nil {
- return nil, err
- }
- {
- digestMethodEl := ciphertextEl.FindElement("./EncryptionMethod/DigestMethod")
- if digestMethodEl == nil {
- e.DigestMethod = SHA1
- } else {
- hashAlgorithmStr := digestMethodEl.SelectAttrValue("Algorithm", "")
- digestMethod, ok := digestMethods[hashAlgorithmStr]
- if !ok {
- return nil, ErrAlgorithmNotImplemented(hashAlgorithmStr)
- }
- e.DigestMethod = digestMethod
- }
- }
- return e.keyDecrypter(e, rsaKey, ciphertext)
- }
- // OAEP returns a version of RSA that implements RSA in OAEP-MGF1P mode. By default
- // the block cipher used is AES-256 CBC and the digest method is SHA-256. You can
- // specify other ciphers and digest methods by assigning to BlockCipher or
- // DigestMethod.
- func OAEP() RSA {
- return RSA{
- BlockCipher: AES256CBC,
- DigestMethod: SHA256,
- algorithm: "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p",
- keyEncrypter: func(e RSA, pubKey *rsa.PublicKey, plaintext []byte) ([]byte, error) {
- return rsa.EncryptOAEP(e.DigestMethod.Hash(), RandReader, pubKey, plaintext, nil)
- },
- keyDecrypter: func(e RSA, privKey *rsa.PrivateKey, ciphertext []byte) ([]byte, error) {
- return rsa.DecryptOAEP(e.DigestMethod.Hash(), RandReader, privKey, ciphertext, nil)
- },
- }
- }
- // PKCS1v15 returns a version of RSA that implements RSA in PKCS1v15 mode. By default
- // the block cipher used is AES-256 CBC. The DigestMethod field is ignored because PKCS1v15
- // does not use a digest function.
- func PKCS1v15() RSA {
- return RSA{
- BlockCipher: AES256CBC,
- DigestMethod: nil,
- algorithm: "http://www.w3.org/2001/04/xmlenc#rsa-1_5",
- keyEncrypter: func(e RSA, pubKey *rsa.PublicKey, plaintext []byte) ([]byte, error) {
- return rsa.EncryptPKCS1v15(RandReader, pubKey, plaintext)
- },
- keyDecrypter: func(e RSA, privKey *rsa.PrivateKey, ciphertext []byte) ([]byte, error) {
- return rsa.DecryptPKCS1v15(RandReader, privKey, ciphertext)
- },
- }
- }
- func init() {
- RegisterDecrypter(OAEP())
- RegisterDecrypter(PKCS1v15())
- }
|