clean up, add documentation, fix lint errors
This commit is contained in:
131
encrypt.go
131
encrypt.go
@@ -21,44 +21,87 @@ package xmlsec
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"errors"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// SessionCipherType represents which session cipher to use to encrypt the document.
|
||||
type SessionCipherType int
|
||||
|
||||
const (
|
||||
DefaultAlgorithm = iota
|
||||
// DefaultSessionCipher (the zero value) represents the default session cipher, AES256-CBC
|
||||
DefaultSessionCipher SessionCipherType = iota
|
||||
|
||||
// Aes128Cbc means the session cipher should be AES-128 in CBC mode.
|
||||
Aes128Cbc
|
||||
|
||||
// Aes192Cbc means the session cipher should be AES-192 in CBC mode.
|
||||
Aes192Cbc
|
||||
|
||||
// Aes256Cbc means the session cipher should be AES-256 in CBC mode.
|
||||
Aes256Cbc
|
||||
|
||||
// Des3Cbc means the session cipher should be triple DES in CBC mode.
|
||||
Des3Cbc
|
||||
DsaSha1
|
||||
Sha1
|
||||
Sha256
|
||||
Sha384
|
||||
Sha512
|
||||
)
|
||||
|
||||
// CipherType represent which cipher to use to encrypt the document
|
||||
type CipherType int
|
||||
|
||||
const (
|
||||
// DefaultCipher (the zero value) represents the default cipher, RSA-OAEP
|
||||
DefaultCipher CipherType = iota
|
||||
|
||||
// RsaOaep means the cipher should be RSA-OAEP
|
||||
RsaOaep
|
||||
|
||||
// RsaPkcs1 means the cipher should be RSA-PKCS1
|
||||
RsaPkcs1
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
SessionCipher int
|
||||
Cipher int
|
||||
DigestAlgorithm int
|
||||
// DigestAlgorithmType represent which digest algorithm to use when encrypting the document.
|
||||
type DigestAlgorithmType int
|
||||
|
||||
const (
|
||||
// DefaultDigestAlgorithm (the zero value) represents the default cipher, SHA1
|
||||
DefaultDigestAlgorithm DigestAlgorithmType = iota
|
||||
|
||||
// Sha1 means the digest algorithm should be SHA-1
|
||||
Sha1
|
||||
|
||||
// Sha256 means the digest algorithm should be SHA-256
|
||||
Sha256
|
||||
|
||||
// Sha384 means the digest algorithm should be SHA-384
|
||||
Sha384
|
||||
|
||||
// Sha512 means the digest algorithm should be SHA-512
|
||||
Sha512
|
||||
)
|
||||
|
||||
// EncryptOptions specifies the ciphers to use to encrypt the document.
|
||||
type EncryptOptions struct {
|
||||
SessionCipher SessionCipherType
|
||||
Cipher CipherType
|
||||
DigestAlgorithm DigestAlgorithmType
|
||||
}
|
||||
|
||||
// XmlEncrypt encrypts the XML document to publicKey.
|
||||
func XmlEncrypt(publicKey, doc []byte, opts Options) ([]byte, error) {
|
||||
var errInvalidAlgorithm = errors.New("invalid algorithm")
|
||||
|
||||
// Encrypt encrypts the XML document to publicKey and returns the encrypted
|
||||
// document.
|
||||
func Encrypt(publicKey, doc []byte, opts EncryptOptions) ([]byte, error) {
|
||||
startProcessingXML()
|
||||
defer stopProcessingXML()
|
||||
|
||||
keysMngr := C.xmlSecKeysMngrCreate()
|
||||
if keysMngr == nil {
|
||||
return nil, fmt.Errorf("xmlSecKeysMngrCreate failed")
|
||||
return nil, mustPopError()
|
||||
}
|
||||
defer C.xmlSecKeysMngrDestroy(keysMngr)
|
||||
|
||||
if rv := C.xmlSecCryptoAppDefaultKeysMngrInit(keysMngr); rv < 0 {
|
||||
return nil, fmt.Errorf("xmlSecCryptoAppDefaultKeysMngrInit failed")
|
||||
return nil, mustPopError()
|
||||
}
|
||||
|
||||
key := C.xmlSecCryptoAppKeyLoadMemory(
|
||||
@@ -67,7 +110,7 @@ func XmlEncrypt(publicKey, doc []byte, opts Options) ([]byte, error) {
|
||||
C.xmlSecKeyDataFormatCertPem,
|
||||
nil, nil, nil)
|
||||
if key == nil {
|
||||
return nil, fmt.Errorf("xmlSecCryptoAppKeyLoadMemory failed")
|
||||
return nil, mustPopError()
|
||||
}
|
||||
|
||||
if rv := C.xmlSecCryptoAppKeyCertLoadMemory(key,
|
||||
@@ -75,11 +118,11 @@ func XmlEncrypt(publicKey, doc []byte, opts Options) ([]byte, error) {
|
||||
C.xmlSecSize(len(publicKey)),
|
||||
C.xmlSecKeyDataFormatCertPem); rv < 0 {
|
||||
C.xmlSecKeyDestroy(key)
|
||||
return nil, fmt.Errorf("xmlSecCryptoAppKeyCertLoad failed")
|
||||
return nil, mustPopError()
|
||||
}
|
||||
|
||||
if rv := C.xmlSecCryptoAppDefaultKeysMngrAdoptKey(keysMngr, key); rv < 0 {
|
||||
return nil, fmt.Errorf("xmlSecCryptoAppDefaultKeysMngrAdoptKey failed")
|
||||
return nil, mustPopError()
|
||||
}
|
||||
|
||||
parsedDoc, err := newDoc(doc)
|
||||
@@ -90,7 +133,7 @@ func XmlEncrypt(publicKey, doc []byte, opts Options) ([]byte, error) {
|
||||
|
||||
var sessionCipherTransform C.xmlSecTransformId
|
||||
switch opts.SessionCipher {
|
||||
case DefaultAlgorithm:
|
||||
case DefaultSessionCipher:
|
||||
sessionCipherTransform = C.MY_xmlSecTransformAes256CbcId()
|
||||
case Aes256Cbc:
|
||||
sessionCipherTransform = C.MY_xmlSecTransformAes256CbcId()
|
||||
@@ -101,7 +144,7 @@ func XmlEncrypt(publicKey, doc []byte, opts Options) ([]byte, error) {
|
||||
case Des3Cbc:
|
||||
sessionCipherTransform = C.MY_xmlSecTransformDes3CbcId()
|
||||
default:
|
||||
return nil, fmt.Errorf("XXX")
|
||||
return nil, errInvalidAlgorithm
|
||||
}
|
||||
|
||||
// create encryption template to encrypt XML file and replace
|
||||
@@ -109,7 +152,7 @@ func XmlEncrypt(publicKey, doc []byte, opts Options) ([]byte, error) {
|
||||
encDataNode := C.xmlSecTmplEncDataCreate(parsedDoc, sessionCipherTransform,
|
||||
nil, (*C.xmlChar)(unsafe.Pointer(&C.xmlSecTypeEncElement)), nil, nil)
|
||||
if encDataNode == nil {
|
||||
return nil, fmt.Errorf("xmlSecTmplEncDataCreate failed")
|
||||
return nil, mustPopError()
|
||||
}
|
||||
defer func() {
|
||||
if encDataNode != nil {
|
||||
@@ -120,19 +163,19 @@ func XmlEncrypt(publicKey, doc []byte, opts Options) ([]byte, error) {
|
||||
|
||||
// we want to put encrypted data in the <enc:CipherValue/> node
|
||||
if C.xmlSecTmplEncDataEnsureCipherValue(encDataNode) == nil {
|
||||
return nil, fmt.Errorf("xmlSecTmplEncDataEnsureCipherValue failed")
|
||||
return nil, mustPopError()
|
||||
}
|
||||
|
||||
// add <dsig:KeyInfo/>
|
||||
keyInfoNode := C.xmlSecTmplEncDataEnsureKeyInfo(encDataNode, nil)
|
||||
if keyInfoNode == nil {
|
||||
return nil, fmt.Errorf("xmlSecTmplEncDataEnsureKeyInfo failed")
|
||||
return nil, mustPopError()
|
||||
}
|
||||
|
||||
// add <enc:EncryptedKey/> to store the encrypted session key
|
||||
var cipherTransform C.xmlSecTransformId
|
||||
switch opts.Cipher {
|
||||
case DefaultAlgorithm:
|
||||
case DefaultCipher:
|
||||
cipherTransform = C.MY_xmlSecTransformRsaOaepId()
|
||||
case RsaOaep:
|
||||
cipherTransform = C.MY_xmlSecTransformRsaOaepId()
|
||||
@@ -141,39 +184,39 @@ func XmlEncrypt(publicKey, doc []byte, opts Options) ([]byte, error) {
|
||||
}
|
||||
encKeyNode := C.xmlSecTmplKeyInfoAddEncryptedKey(keyInfoNode, cipherTransform, nil, nil, nil)
|
||||
if encKeyNode == nil {
|
||||
return nil, fmt.Errorf("xmlSecTmplKeyInfoAddEncryptedKey failed")
|
||||
return nil, mustPopError()
|
||||
}
|
||||
|
||||
// we want to put encrypted key in the <enc:CipherValue/> node
|
||||
if C.xmlSecTmplEncDataEnsureCipherValue(encKeyNode) == nil {
|
||||
return nil, fmt.Errorf("xmlSecTmplEncDataEnsureCipherValue failed")
|
||||
return nil, mustPopError()
|
||||
}
|
||||
|
||||
// add <dsig:KeyInfo/> and <dsig:KeyName/> nodes to <enc:EncryptedKey/>
|
||||
keyInfoNode2 := C.xmlSecTmplEncDataEnsureKeyInfo(encKeyNode, nil)
|
||||
if keyInfoNode2 == nil {
|
||||
return nil, fmt.Errorf("xmlSecTmplEncDataEnsureKeyInfo failed")
|
||||
return nil, mustPopError()
|
||||
}
|
||||
// Add a DigestMethod element to the encryption method node
|
||||
{
|
||||
encKeyMethod := C.xmlSecTmplEncDataGetEncMethodNode(encKeyNode)
|
||||
var ns = constXmlChar("http://www.w3.org/2000/09/xmldsig#")
|
||||
var strDigestMethod = constXmlChar("DigestMethod")
|
||||
var strAlgorithm = constXmlChar("Algorithm")
|
||||
var ns = constXMLChar("http://www.w3.org/2000/09/xmldsig#")
|
||||
var strDigestMethod = constXMLChar("DigestMethod")
|
||||
var strAlgorithm = constXMLChar("Algorithm")
|
||||
var algorithm *C.xmlChar
|
||||
switch opts.DigestAlgorithm {
|
||||
case Sha512:
|
||||
algorithm = constXmlChar("http://www.w3.org/2001/04/xmlenc#sha512")
|
||||
algorithm = constXMLChar("http://www.w3.org/2001/04/xmlenc#sha512")
|
||||
case Sha384:
|
||||
algorithm = constXmlChar("http://www.w3.org/2001/04/xmldsig-more#sha384")
|
||||
algorithm = constXMLChar("http://www.w3.org/2001/04/xmldsig-more#sha384")
|
||||
case Sha256:
|
||||
algorithm = constXmlChar("http://www.w3.org/2001/04/xmlenc#sha256")
|
||||
algorithm = constXMLChar("http://www.w3.org/2001/04/xmlenc#sha256")
|
||||
case Sha1:
|
||||
algorithm = constXmlChar("http://www.w3.org/2000/09/xmldsig#sha1")
|
||||
case DefaultAlgorithm:
|
||||
algorithm = constXmlChar("http://www.w3.org/2000/09/xmldsig#sha1")
|
||||
algorithm = constXMLChar("http://www.w3.org/2000/09/xmldsig#sha1")
|
||||
case DefaultDigestAlgorithm:
|
||||
algorithm = constXMLChar("http://www.w3.org/2000/09/xmldsig#sha1")
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown digest algorithm %d", opts.DigestAlgorithm)
|
||||
return nil, errInvalidAlgorithm
|
||||
}
|
||||
node := C.xmlSecAddChild(encKeyMethod, strDigestMethod, ns)
|
||||
C.xmlSetProp(node, strAlgorithm, algorithm)
|
||||
@@ -182,22 +225,22 @@ func XmlEncrypt(publicKey, doc []byte, opts Options) ([]byte, error) {
|
||||
// add our certificate to KeyInfoNode
|
||||
x509dataNode := C.xmlSecTmplKeyInfoAddX509Data(keyInfoNode2)
|
||||
if x509dataNode == nil {
|
||||
return nil, fmt.Errorf("xmlSecTmplKeyInfoAddX509Data failed")
|
||||
return nil, mustPopError()
|
||||
}
|
||||
if dataNode := C.xmlSecTmplX509DataAddCertificate(x509dataNode); dataNode == nil {
|
||||
return nil, fmt.Errorf("xmlSecTmplX509DataAddCertificate failed")
|
||||
return nil, mustPopError()
|
||||
}
|
||||
|
||||
// create encryption context
|
||||
var encCtx = C.xmlSecEncCtxCreate(keysMngr)
|
||||
if encCtx == nil {
|
||||
return nil, fmt.Errorf("xmlSecEncCtxCreate failed")
|
||||
return nil, mustPopError()
|
||||
}
|
||||
defer C.xmlSecEncCtxDestroy(encCtx)
|
||||
|
||||
// generate a key of the appropriate type
|
||||
switch opts.SessionCipher {
|
||||
case DefaultAlgorithm:
|
||||
case DefaultSessionCipher:
|
||||
encCtx.encKey = C.xmlSecKeyGenerate(C.MY_xmlSecKeyDataAesId(), 256,
|
||||
C.xmlSecKeyDataTypeSession)
|
||||
case Aes128Cbc:
|
||||
@@ -213,15 +256,15 @@ func XmlEncrypt(publicKey, doc []byte, opts Options) ([]byte, error) {
|
||||
encCtx.encKey = C.xmlSecKeyGenerate(C.MY_xmlSecKeyDataDesId(), 192,
|
||||
C.xmlSecKeyDataTypeSession)
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown cipher type %d", opts.SessionCipher)
|
||||
return nil, errInvalidAlgorithm
|
||||
}
|
||||
if encCtx.encKey == nil {
|
||||
return nil, fmt.Errorf("xmlSecKeyGenerate failed")
|
||||
return nil, mustPopError()
|
||||
}
|
||||
|
||||
// encrypt the data
|
||||
if rv := C.xmlSecEncCtxXmlEncrypt(encCtx, encDataNode, C.xmlDocGetRootElement(parsedDoc)); rv < 0 {
|
||||
return nil, fmt.Errorf("xmlSecEncCtxXmlEncrypt failed")
|
||||
return nil, mustPopError()
|
||||
}
|
||||
encDataNode = nil // the template is inserted in the doc, so we don't own it
|
||||
|
||||
|
||||
Reference in New Issue
Block a user