Initial QSfera import
This commit is contained in:
+162
@@ -0,0 +1,162 @@
|
||||
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, nonce []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, nonce)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
encryptedDataEl.InsertChildAt(encryptedDataEl.FindElement("./CipherData").Index(), 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 := validateRSAKeyIfPresent(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())
|
||||
}
|
||||
Reference in New Issue
Block a user