Initial QSfera import

This commit is contained in:
Курнат Андрей
2026-06-07 10:20:04 +03:00
commit 2315f25754
16485 changed files with 4826827 additions and 0 deletions
+187
View File
@@ -0,0 +1,187 @@
package xmlenc
import (
"crypto/aes"
"crypto/cipher"
"crypto/des" // nolint: gas
"encoding/base64"
"errors"
"fmt"
"github.com/beevik/etree"
)
// CBC implements Decrypter and Encrypter for block ciphers in CBC mode
type CBC struct {
keySize int
algorithm string
cipher func([]byte) (cipher.Block, error)
}
// KeySize returns the length of the key required.
func (e CBC) KeySize() int {
return e.keySize
}
// Algorithm returns the name of the algorithm, as will be found
// in an xenc:EncryptionMethod element.
func (e CBC) Algorithm() string {
return e.algorithm
}
// Encrypt encrypts plaintext with key, which should be a []byte of length KeySize().
// It returns an xenc:EncryptedData element.
func (e CBC) Encrypt(key interface{}, plaintext []byte, _ []byte) (*etree.Element, error) {
keyBuf, ok := key.([]byte)
if !ok {
return nil, ErrIncorrectKeyType("[]byte")
}
if len(keyBuf) != e.keySize {
return nil, ErrIncorrectKeyLength(e.keySize)
}
block, err := e.cipher(keyBuf)
if err != nil {
return nil, err
}
encryptedDataEl := etree.NewElement("xenc:EncryptedData")
encryptedDataEl.CreateAttr("xmlns:xenc", "http://www.w3.org/2001/04/xmlenc#")
{
randBuf := make([]byte, 16)
if _, err := RandReader.Read(randBuf); err != nil {
return nil, err
}
encryptedDataEl.CreateAttr("Id", fmt.Sprintf("_%x", randBuf))
}
em := encryptedDataEl.CreateElement("xenc:EncryptionMethod")
em.CreateAttr("Algorithm", e.algorithm)
em.CreateAttr("xmlns:xenc", "http://www.w3.org/2001/04/xmlenc#")
plaintext = appendPadding(plaintext, block.BlockSize())
iv := make([]byte, block.BlockSize())
if _, err := RandReader.Read(iv); err != nil {
return nil, err
}
mode := cipher.NewCBCEncrypter(block, iv)
ciphertext := make([]byte, len(plaintext))
mode.CryptBlocks(ciphertext, plaintext)
ciphertext = append(iv, ciphertext...)
cd := encryptedDataEl.CreateElement("xenc:CipherData")
cd.CreateAttr("xmlns:xenc", "http://www.w3.org/2001/04/xmlenc#")
cd.CreateElement("xenc:CipherValue").SetText(base64.StdEncoding.EncodeToString(ciphertext))
return encryptedDataEl, nil
}
// Decrypt decrypts an encrypted element with key. If the ciphertext contains an
// EncryptedKey element, then the type of `key` is determined by the registered
// Decryptor for the EncryptedKey element. Otherwise, `key` must be a []byte of
// length KeySize().
func (e CBC) Decrypt(key interface{}, ciphertextEl *etree.Element) ([]byte, error) {
// If the key is encrypted, decrypt it.
if encryptedKeyEl := ciphertextEl.FindElement("./KeyInfo/EncryptedKey"); encryptedKeyEl != nil {
var err error
key, err = Decrypt(key, encryptedKeyEl)
if err != nil {
return nil, err
}
}
keyBuf, ok := key.([]byte)
if !ok {
return nil, ErrIncorrectKeyType("[]byte")
}
if len(keyBuf) != e.KeySize() {
return nil, ErrIncorrectKeyLength(e.KeySize())
}
block, err := e.cipher(keyBuf)
if err != nil {
return nil, err
}
ciphertext, err := getCiphertext(ciphertextEl)
if err != nil {
return nil, err
}
if len(ciphertext) < block.BlockSize() {
return nil, errors.New("ciphertext too short")
}
iv := ciphertext[:aes.BlockSize]
ciphertext = ciphertext[aes.BlockSize:]
mode := cipher.NewCBCDecrypter(block, iv)
plaintext := make([]byte, len(ciphertext))
mode.CryptBlocks(plaintext, ciphertext) // decrypt in place
plaintext, err = stripPadding(plaintext)
if err != nil {
return nil, err
}
return plaintext, nil
}
var (
// AES128CBC implements AES128-CBC symetric key mode for encryption and decryption
AES128CBC BlockCipher = CBC{
keySize: 16,
algorithm: "http://www.w3.org/2001/04/xmlenc#aes128-cbc",
cipher: aes.NewCipher,
}
// AES192CBC implements AES192-CBC symetric key mode for encryption and decryption
AES192CBC BlockCipher = CBC{
keySize: 24,
algorithm: "http://www.w3.org/2001/04/xmlenc#aes192-cbc",
cipher: aes.NewCipher,
}
// AES256CBC implements AES256-CBC symetric key mode for encryption and decryption
AES256CBC BlockCipher = CBC{
keySize: 32,
algorithm: "http://www.w3.org/2001/04/xmlenc#aes256-cbc",
cipher: aes.NewCipher,
}
// TripleDES implements 3DES in CBC mode for encryption and decryption
TripleDES BlockCipher = CBC{
keySize: 8,
algorithm: "http://www.w3.org/2001/04/xmlenc#tripledes-cbc",
cipher: des.NewCipher,
}
)
func init() {
RegisterDecrypter(AES128CBC)
RegisterDecrypter(AES192CBC)
RegisterDecrypter(AES256CBC)
RegisterDecrypter(TripleDES)
}
func appendPadding(buf []byte, blockSize int) []byte {
paddingBytes := blockSize - (len(buf) % blockSize)
padding := make([]byte, paddingBytes)
padding[len(padding)-1] = byte(paddingBytes)
return append(buf, padding...)
}
func stripPadding(buf []byte) ([]byte, error) {
if len(buf) < 1 {
return nil, errors.New("buffer is too short for padding")
}
paddingBytes := int(buf[len(buf)-1])
if paddingBytes > len(buf)-1 {
return nil, errors.New("buffer is too short for padding")
}
if paddingBytes < 1 {
return nil, errors.New("padding must be at least one byte")
}
return buf[:len(buf)-paddingBytes], nil
}
+116
View File
@@ -0,0 +1,116 @@
package xmlenc
import (
// nolint: gas
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"errors"
"fmt"
"strings"
"github.com/beevik/etree"
)
// ErrAlgorithmNotImplemented is returned when encryption used is not
// supported.
type ErrAlgorithmNotImplemented string
func (e ErrAlgorithmNotImplemented) Error() string {
return "algorithm is not implemented: " + string(e)
}
// ErrCannotFindRequiredElement is returned by Decrypt when a required
// element cannot be found.
type ErrCannotFindRequiredElement string
func (e ErrCannotFindRequiredElement) Error() string {
return "cannot find required element: " + string(e)
}
// ErrIncorrectTag is returned when Decrypt is passed an element which
// is neither an EncryptedType nor an EncryptedKey
var ErrIncorrectTag = fmt.Errorf("tag must be an EncryptedType or EncryptedKey")
// ErrIncorrectKeyLength is returned when the fixed length key is not
// of the required length.
type ErrIncorrectKeyLength int
func (e ErrIncorrectKeyLength) Error() string {
return fmt.Sprintf("expected key to be %d bytes", int(e))
}
// ErrIncorrectKeyType is returned when the key is not the correct type
type ErrIncorrectKeyType string
func (e ErrIncorrectKeyType) Error() string {
return fmt.Sprintf("expected key to be %s", string(e))
}
// Decrypt decrypts the encrypted data using the provided key. If the
// data are encrypted using AES or 3DEC, then the key should be a []byte.
// If the data are encrypted with PKCS1v15 or RSA-OAEP-MGF1P then key should
// be a *rsa.PrivateKey.
func Decrypt(key interface{}, ciphertextEl *etree.Element) ([]byte, error) {
encryptionMethodEl := ciphertextEl.FindElement("./EncryptionMethod")
if encryptionMethodEl == nil {
return nil, ErrCannotFindRequiredElement("EncryptionMethod")
}
algorithm := encryptionMethodEl.SelectAttrValue("Algorithm", "")
decrypter, ok := decrypters[algorithm]
if !ok {
return nil, ErrAlgorithmNotImplemented(algorithm)
}
return decrypter.Decrypt(key, ciphertextEl)
}
func getCiphertext(encryptedKey *etree.Element) ([]byte, error) {
ciphertextEl := encryptedKey.FindElement("./CipherData/CipherValue")
if ciphertextEl == nil {
return nil, fmt.Errorf("cannot find CipherData element containing a CipherValue element")
}
ciphertext, err := base64.StdEncoding.DecodeString(strings.TrimSpace(ciphertextEl.Text()))
if err != nil {
return nil, err
}
return ciphertext, nil
}
func validateRSAKeyIfPresent(key interface{}, encryptedKey *etree.Element) (*rsa.PrivateKey, error) {
rsaKey, ok := key.(*rsa.PrivateKey)
if !ok {
return nil, errors.New("expected key to be a *rsa.PrivateKey")
}
// extract and verify that the public key matches the certificate
// this section is included to either let the service know up front
// if the key will work, or let the service provider know which key
// to use to decrypt the message. Either way, verification is not
// security-critical.
//nolint:revive,staticcheck // Keep the later empty branch so that we know to address this at a later date.
if el := encryptedKey.FindElement("./KeyInfo/X509Data/X509Certificate"); el != nil {
certPEMbuf := el.Text()
certPEMbuf = "-----BEGIN CERTIFICATE-----\n" + certPEMbuf + "\n-----END CERTIFICATE-----\n"
certPEM, _ := pem.Decode([]byte(certPEMbuf))
if certPEM == nil {
return nil, fmt.Errorf("invalid certificate")
}
cert, err := x509.ParseCertificate(certPEM.Bytes)
if err != nil {
return nil, err
}
pubKey, ok := cert.PublicKey.(*rsa.PublicKey)
if !ok {
return nil, fmt.Errorf("expected certificate to be an *rsa.PublicKey")
}
if rsaKey.N.Cmp(pubKey.N) != 0 || rsaKey.E != pubKey.E {
return nil, fmt.Errorf("certificate does not match provided key")
}
} else if el = encryptedKey.FindElement("./KeyInfo/X509Data/X509IssuerSerial"); el != nil {
// TODO: determine how to validate the issuer serial information
}
return rsaKey, nil
}
+57
View File
@@ -0,0 +1,57 @@
package xmlenc
import (
"crypto/sha1" //nolint:gosec // required for protocol support
"crypto/sha256"
"crypto/sha512"
"hash"
//nolint:staticcheck // We should support this for legacy reasons.
"golang.org/x/crypto/ripemd160"
)
type digestMethod struct {
algorithm string
hash func() hash.Hash
}
func (dm digestMethod) Algorithm() string {
return dm.algorithm
}
func (dm digestMethod) Hash() hash.Hash {
return dm.hash()
}
var (
// SHA1 implements the SHA-1 digest method (which is considered insecure)
SHA1 = digestMethod{
algorithm: "http://www.w3.org/2000/09/xmldsig#sha1",
hash: sha1.New,
}
// SHA256 implements the SHA-256 digest method
SHA256 = digestMethod{
algorithm: "http://www.w3.org/2000/09/xmldsig#sha256",
hash: sha256.New,
}
// SHA512 implements the SHA-512 digest method
SHA512 = digestMethod{
algorithm: "http://www.w3.org/2000/09/xmldsig#sha512",
hash: sha512.New,
}
// RIPEMD160 implements the RIPEMD160 digest method
RIPEMD160 = digestMethod{
algorithm: "http://www.w3.org/2000/09/xmldsig#ripemd160",
hash: ripemd160.New,
}
)
func init() {
RegisterDigestMethod(SHA1)
RegisterDigestMethod(SHA256)
RegisterDigestMethod(SHA512)
RegisterDigestMethod(RIPEMD160)
}
+49
View File
@@ -0,0 +1,49 @@
package xmlenc
import (
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"github.com/beevik/etree"
)
var testKey = func() *rsa.PrivateKey {
const keyStr = `-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDkXTUsWzRVpUHjbDpWCfYDfXmQ/q4LkaioZoTpu4ut1Q3eQC5t
gD14agJhgT8yzeY5S/YNlwCyuVkjuFyoyTHFX2IOPpz7jnh4KnQ+B1IH9fY/+kmk
zHJgxSUDJsdUMPgGpKt5hnEn7ziXAWXLc2udFbnHwhi9TXXwRHGi9wZ4YwIDAQAB
AoGBALNTnlXeqRI4W61DZ+v4ln/XIIeD9xiOoWrcVrNU2zL+g41ryQmkEqFkXcpD
vGUg2xFTXTz+v0WZ1y39sIW6uKFRYUfaNsF6iVfGAyx1VWK/jgtPnCWDQy26Eby0
BqpbZRy1a6MLYVEG/5bvZE01CDV4XttpTrNX91WWcYGduJxBAkEA6ED1ZOqIzBpu
c2KAo+bWmroCH8+cSDk0gVq6bnRB+EEhRCmo/VgvndWLxfexdGmDIOAIisB06N5a
GzBSCaEY/QJBAPu2cNvuuBNLwrlxPCwOEpIHYT4gJq8UMtg6O6N+u++nYCGhK6uo
VCmrKY+UewyNIcsLZF0jsNI2qJjiU1vQxN8CQQDfQJnigMQwlfO3/Ga1po6Buu2R
0IpkroB3G1R8GkrTrR+iGv2zUdKrwHsUOC2fPlFrB4+OeMOomRw6aG9jjDStAkB1
ztiZhuvuVAoKIv5HnDqC0CNqIUAZtzlozDB3f+xT6SFr+/Plfn4Nlod4JMVGhZNo
ZaeOlBLBAEX+cAcVtOs/AkBicZOAPv84ABmFfyhXhYaAuacaJLq//jg+t+URUOg+
XZS9naRmawEQxOkZQVoMeKgvu05+V4MniFqdQBINIkr5
-----END RSA PRIVATE KEY-----`
b, _ := pem.Decode([]byte(keyStr))
k, err := x509.ParsePKCS1PrivateKey(b.Bytes)
if err != nil {
panic(err)
}
return k
}()
// Fuzz is the go-fuzz fuzzing function
func Fuzz(data []byte) int {
doc := etree.NewDocument()
if err := doc.ReadFromBytes(data); err != nil {
return 0
}
if doc.Root() == nil {
return 0
}
if _, err := Decrypt(testKey, doc.Root()); err != nil {
return 0
}
return 1
}
+143
View File
@@ -0,0 +1,143 @@
package xmlenc
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/base64"
"fmt"
"io"
"github.com/beevik/etree"
)
// GCM implements Decrypter and Encrypter for block ciphers in struct mode
type GCM struct {
keySize int
algorithm string
cipher func([]byte) (cipher.Block, error)
}
// KeySize returns the length of the key required.
func (e GCM) KeySize() int {
return e.keySize
}
// Algorithm returns the name of the algorithm, as will be found
// in an xenc:EncryptionMethod element.
func (e GCM) Algorithm() string {
return e.algorithm
}
// Encrypt encrypts plaintext with key and nonce
func (e GCM) Encrypt(key interface{}, plaintext []byte, nonce []byte) (*etree.Element, error) {
keyBuf, ok := key.([]byte)
if !ok {
return nil, ErrIncorrectKeyType("[]byte")
}
if len(keyBuf) != e.keySize {
return nil, ErrIncorrectKeyLength(e.keySize)
}
block, err := e.cipher(keyBuf)
if err != nil {
return nil, err
}
encryptedDataEl := etree.NewElement("xenc:EncryptedData")
encryptedDataEl.CreateAttr("xmlns:xenc", "http://www.w3.org/2001/04/xmlenc#")
{
randBuf := make([]byte, 16)
if _, err := RandReader.Read(randBuf); err != nil {
return nil, err
}
encryptedDataEl.CreateAttr("Id", fmt.Sprintf("_%x", randBuf))
}
em := encryptedDataEl.CreateElement("xenc:EncryptionMethod")
em.CreateAttr("Algorithm", e.algorithm)
em.CreateAttr("xmlns:xenc", "http://www.w3.org/2001/04/xmlenc#")
plaintext = appendPadding(plaintext, block.BlockSize())
aesgcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
if nonce == nil {
// generate random nonce when it's nil
nonce := make([]byte, aesgcm.NonceSize())
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
panic(err.Error())
}
}
ciphertext := make([]byte, len(plaintext))
text := aesgcm.Seal(nil, nonce, ciphertext, nil)
cd := encryptedDataEl.CreateElement("xenc:CipherData")
cd.CreateAttr("xmlns:xenc", "http://www.w3.org/2001/04/xmlenc#")
cd.CreateElement("xenc:CipherValue").SetText(base64.StdEncoding.EncodeToString(text))
return encryptedDataEl, nil
}
// Decrypt decrypts an encrypted element with key. If the ciphertext contains an
// EncryptedKey element, then the type of `key` is determined by the registered
// Decryptor for the EncryptedKey element. Otherwise, `key` must be a []byte of
// length KeySize().
func (e GCM) Decrypt(key interface{}, ciphertextEl *etree.Element) ([]byte, error) {
if encryptedKeyEl := ciphertextEl.FindElement("./KeyInfo/EncryptedKey"); encryptedKeyEl != nil {
var err error
key, err = Decrypt(key, encryptedKeyEl)
if err != nil {
return nil, err
}
}
keyBuf, ok := key.([]byte)
if !ok {
return nil, ErrIncorrectKeyType("[]byte")
}
if len(keyBuf) != e.KeySize() {
return nil, ErrIncorrectKeyLength(e.KeySize())
}
block, err := e.cipher(keyBuf)
if err != nil {
return nil, err
}
aesgcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
ciphertext, err := getCiphertext(ciphertextEl)
if err != nil {
return nil, err
}
nonce := ciphertext[:aesgcm.NonceSize()]
text := ciphertext[aesgcm.NonceSize():]
plainText, err := aesgcm.Open(nil, nonce, text, nil)
if err != nil {
return nil, err
}
return plainText, nil
}
var (
// AES128GCM implements AES128-GCM mode for encryption and decryption
AES128GCM BlockCipher = GCM{
keySize: 16,
algorithm: "http://www.w3.org/2009/xmlenc11#aes128-gcm",
cipher: aes.NewCipher,
}
)
func init() {
RegisterDecrypter(AES128GCM)
}
+162
View File
@@ -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())
}
+62
View File
@@ -0,0 +1,62 @@
// Package xmlenc is a partial implementation of the xmlenc standard
// as described in https://www.w3.org/TR/2002/REC-xmlenc-core-20021210/Overview.html.
// The purpose of this implementation is to support encrypted SAML assertions.
package xmlenc
import (
"crypto/rand"
"hash"
"github.com/beevik/etree"
)
// RandReader is a thunk that allows test to replace the source of randomness used by
// this package. By default it is Reader from crypto/rand.
var RandReader = rand.Reader
// Encrypter is an interface that encrypts things. Given a plaintext it returns an
// XML EncryptedData or EncryptedKey element. The required type of `key` varies
// depending on the implementation.
type Encrypter interface {
Encrypt(key interface{}, plaintext []byte, nonce []byte) (*etree.Element, error)
}
// Decrypter is an interface that decrypts things. The Decrypt() method returns the
// plaintext version of the EncryptedData or EncryptedKey element passed.
//
// You probably don't have to use this interface directly, instead you may call
// Decrypt() and it will examine the element to determine which Decrypter to use.
type Decrypter interface {
Algorithm() string
Decrypt(key interface{}, ciphertextEl *etree.Element) ([]byte, error)
}
// DigestMethod represents a digest method such as SHA1, etc.
type DigestMethod interface {
Algorithm() string
Hash() hash.Hash
}
var (
decrypters = map[string]Decrypter{}
digestMethods = map[string]DigestMethod{}
)
// RegisterDecrypter registers the specified decrypter to that it can be
// used with Decrypt().
func RegisterDecrypter(d Decrypter) {
decrypters[d.Algorithm()] = d
}
// RegisterDigestMethod registers the specified digest method to that it can be
// used with Decrypt().
func RegisterDigestMethod(dm DigestMethod) {
digestMethods[dm.Algorithm()] = dm
}
// BlockCipher implements a cipher with a fixed size key like AES or 3DES.
type BlockCipher interface {
Encrypter
Decrypter
KeySize() int
}