diff --git a/README.md b/README.md
index 3d329e3..8719a60 100644
--- a/README.md
+++ b/README.md
@@ -24,45 +24,9 @@ A (partial) wrapper for [xmlsec](https://www.aleksey.com/xmlsec).
os.Exit(1)
}
-# Encryption (xmlenc)
+## Decrypting Example
-## Encryption Example
-
- ctx := xmlenc.Context{}
- cert, _ := ioutil.ReadFile("saml.cert.pem")
- err := ctx.AddCert(cert)
- tmplDoc := []byte(``
-
-
-
- Hello, World!
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- `)
- ciphertext, err := ctx.Encrypt(docStr, []byte("Hello, World!"))
-
-## Decryption Example
-
- ctx := xmlenc.Context{}
- key, _ := ioutil.ReadFile("saml.key.pem")
- err := ctx.AddKey(key)
- plaintext, err := ctx.Decrypt(ciphertext)
+ key, _ := ioutil.ReadFile("saml.key")
+ doc, _ := ioutil.ReadAll(os.Stdin)
+ plaintextDoc, err := xmlenc.Decrypt(key, doc)
+ os.Stdout.Write(plaintextDoc)
diff --git a/xmlenc/xmlenc.go b/xmlenc/xmlenc.go
index d12f913..70f8bf0 100644
--- a/xmlenc/xmlenc.go
+++ b/xmlenc/xmlenc.go
@@ -1,351 +1,206 @@
package xmlenc
import (
- "errors"
+ "bytes"
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/des"
+ "crypto/rand"
+ "crypto/rsa"
+ "crypto/sha1"
+ "crypto/x509"
+ "encoding/base64"
+ "encoding/pem"
+ "encoding/xml"
"fmt"
- "unsafe"
+ "hash"
+ "io"
)
-// Note: on mac you need: brew install libxmlsec1 libxml2
+type method struct {
+ Algorithm string `xml:",attr"`
+}
-// #cgo pkg-config: xmlsec1
-// #include
-// #include
-// #include
-// #include
-// #include
+type encryptedData struct {
+ XMLName string `xml:"http://www.w3.org/2001/04/xmlenc# EncryptedData"`
+ ID string `xml:"Id,attr"`
+ Type string `xml:",attr"`
+ EncryptionMethod method `xml:"EncryptionMethod"`
+ KeyInfo keyInfo `xml:"http://www.w3.org/2000/09/xmldsig# KeyInfo"`
+ CipherData *cipherData
+}
+
+type keyInfo struct {
+ XMLName string `xml:"http://www.w3.org/2000/09/xmldsig# KeyInfo"`
+ EncryptedKey *encryptedKey `xml:"http://www.w3.org/2001/04/xmlenc# EncryptedKey"`
+ X509Data x509Data `xml:"http://www.w3.org/2000/09/xmldsig# X509Data"`
+}
+
+type encryptedKey struct {
+ XMLName string `xml:"http://www.w3.org/2001/04/xmlenc# EncryptedKey"`
+ EncryptionMethod *encryptionMethod
+ KeyInfo *keyInfo
+ CipherData *cipherData `xml:"http://www.w3.org/2001/04/xmlenc# CipherData"`
+}
+
+type encryptionMethod struct {
+ Algorithm string `xml:",attr"`
+ DigestMethod method `xml:"http://www.w3.org/2000/09/xmldsig# DigestMethod"`
+}
+
+type x509Data struct {
+ XMLName string `xml:"http://www.w3.org/2000/09/xmldsig# X509Data"`
+ X509Certificate string
+}
+
+type cipherData struct {
+ XMLName string `xml:"http://www.w3.org/2001/04/xmlenc# CipherData"`
+ CipherValue string `xml:"CipherValue"`
+}
+
+// Decrypt searches the serialized XML document `doc` looking for
+// EncryptedData elements and decrypting them. It returns the
+// original document with the each EncryptedData element replaced
+// by the derived plaintext.
//
-// static inline xmlSecKeyDataId MY_xmlSecKeyDataDesId() {
-// return xmlSecOpenSSLKeyDataDesGetKlass();
-// }
-// static inline xmlSecKeyDataId MY_xmlSecKeyDataDsaId() {
-// return xmlSecOpenSSLKeyDataDsaGetKlass();
-// }
-// static inline xmlSecKeyDataId MY_xmlSecKeyDataEcdsaId() {
-// return xmlSecOpenSSLKeyDataEcdsaGetKlass();
-// }
-// static inline xmlSecKeyDataId MY_xmlSecKeyDataRsaId() {
-// return xmlSecOpenSSLKeyDataRsaGetKlass();
-// }
-//
-import "C"
-
-// #cgo pkg-config: libxml-2.0
-// #include
-// #include
-// #include
-// // Macro wrapper function
-// static inline void MY_xmlFree(void *p) {
-// xmlFree(p);
-// }
-//
-import "C"
-
-func init() {
- C.xmlInitParser()
-
- if rv := C.xmlSecInit(); rv < 0 {
- panic("xmlsec failed to initialize")
- }
-
- if rv := C.xmlSecCryptoAppInit(nil); rv < 0 {
- panic("xmlsec crypto initialization failed.")
- }
- if rv := C.xmlSecCryptoInit(); rv < 0 {
- panic("xmlsec crypto initialization failed.")
- }
-}
-
-func newDoc(buf []byte) (*C.xmlDoc, error) {
- ctx := C.xmlCreateMemoryParserCtxt((*C.char)(unsafe.Pointer(&buf[0])),
- C.int(len(buf)))
- if ctx == nil {
- return nil, errors.New("error creating parser")
- }
- defer C.xmlFreeParserCtxt(ctx)
-
- //C.xmlCtxtUseOptions(ctx, C.int(p.Options))
- C.xmlParseDocument(ctx)
-
- if ctx.wellFormed == C.int(0) {
- return nil, errors.New("malformed XML")
- }
-
- doc := ctx.myDoc
- if doc == nil {
- return nil, errors.New("parse failed")
- }
- return doc, nil
-}
-
-func dumpDoc(doc *C.xmlDoc) []byte {
- var buffer *C.xmlChar
- var bufferSize C.int
- C.xmlDocDumpMemory(doc, &buffer, &bufferSize)
- rv := C.GoStringN((*C.char)(unsafe.Pointer(buffer)), bufferSize)
- C.MY_xmlFree(unsafe.Pointer(buffer))
-
- // TODO(ross): this is totally nasty un-idiomatic, but I'm
- // tired of googling how to copy a []byte from a char*
- return []byte(rv)
-}
-
-func closeDoc(doc *C.xmlDoc) {
- C.xmlFreeDoc(doc)
-}
-
-type Context struct {
- ctx *C.xmlSecEncCtx
- keysMngr *C.xmlSecKeysMngr
-}
-
-func (c *Context) Close() {
- if c.ctx != nil {
- C.xmlSecEncCtxDestroy(c.ctx)
- c.ctx = nil
- }
-
- if c.keysMngr != nil {
- C.xmlSecKeysMngrDestroy(c.keysMngr)
- c.keysMngr = nil
- }
-}
-
-func (c *Context) init() error {
- if c.ctx != nil {
- return nil
- }
-
- c.keysMngr = C.xmlSecKeysMngrCreate()
- if c.keysMngr == nil {
- return errors.New("xmlSecKeysMngrCreate failed")
- }
-
- if rv := C.xmlSecCryptoAppDefaultKeysMngrInit(c.keysMngr); rv < 0 {
- return fmt.Errorf("xmlSecCryptoAppDefaultKeysMngrInit failed: %d", rv)
- }
-
- c.ctx = C.xmlSecEncCtxCreate(c.keysMngr)
- if c.ctx == nil {
- return errors.New("xmlSecEncCtxCreate failed")
- }
-
- return nil
-}
-
-const (
- DES = iota
- DSA
- ECDSA
- RSA
-)
-
-func (c *Context) AddKey(data []byte) error {
- if err := c.init(); err != nil {
- return err
- }
-
- key := C.xmlSecCryptoAppKeyLoadMemory(
- (*C.xmlSecByte)(unsafe.Pointer(&data[0])),
- C.uint(len(data)),
- C.xmlSecKeyDataFormatPem,
- nil,
- nil,
- nil)
- if key == nil {
- return errors.New("xmlSecCryptoAppKeyLoadMemory failed")
- }
-
- name := "k"
- C.xmlSecKeySetName(key, (*C.xmlChar)(unsafe.Pointer(C.CString(name))))
-
- if rv := C.xmlSecCryptoAppDefaultKeysMngrAdoptKey(c.keysMngr, key); rv < 0 {
- return errors.New("xmlSecCryptoAppDefaultKeysMngrAdoptKey failed")
- }
-
- return nil
-}
-
-func (c *Context) AddCert(data []byte) error {
- if err := c.init(); err != nil {
- return err
- }
-
- /*
- var xmlSecKeyType C.xmlSecKeyDataId
- switch keyType {
- case DES:
- xmlSecKeyType = C.MY_xmlSecKeyDataDesId()
- case DSA:
- xmlSecKeyType = C.MY_xmlSecKeyDataDsaId()
- case ECDSA:
- xmlSecKeyType = C.MY_xmlSecKeyDataEcdsaId()
- case RSA:
- xmlSecKeyType = C.MY_xmlSecKeyDataRsaId()
- default:
- return errors.New("unknown key type")
- }
- */
-
- if rv := C.xmlSecCryptoAppKeysMngrCertLoadMemory(c.keysMngr,
- (*C.xmlSecByte)(unsafe.Pointer(&data[0])),
- C.uint(len(data)),
- C.xmlSecKeyDataFormatCertPem, // https://www.aleksey.com/xmlsec/api/xmlsec-keysdata.html#XMLSECKEYDATAFORMAT
- C.xmlSecKeyDataTypePublic); rv < 0 {
- return errors.New("xmlSecCryptoAppKeysMngrCertLoadMemory failed")
- }
-
- return nil
-}
-
-// Encrypt encrypts `plaintext` according to the template `tmplDoc`.
-func (c *Context) Encrypt(tmplDoc []byte, plaintext []byte) ([]byte, error) {
- if err := c.init(); err != nil {
- return nil, err
- }
-
- parsedDoc, err := newDoc(tmplDoc)
- if err != nil {
- return nil, err
- }
- defer closeDoc(parsedDoc)
-
- tmplNode := C.xmlSecFindNode(C.xmlDocGetRootElement(parsedDoc),
- (*C.xmlChar)(unsafe.Pointer(&C.xmlSecNodeEncryptedData)),
- (*C.xmlChar)(unsafe.Pointer(&C.xmlSecEncNs)))
- if tmplNode == nil {
- return nil, errors.New("cannot find start node")
- }
-
- // TODO(ross): actually use the requested cipher
- c.ctx.encKey = C.xmlSecKeyGenerateByName(
- (*C.xmlChar)(unsafe.Pointer(C.CString("aes"))),
- 128, C.xmlSecKeyDataTypeSession)
- if c.ctx.encKey == nil {
- return nil, errors.New("failed to generate session key")
- }
-
- if rv := C.xmlSecEncCtxXmlEncrypt(c.ctx, tmplNode,
- C.xmlDocGetRootElement(parsedDoc)); rv < 0 {
- return nil, errors.New("cannot encrypt")
- }
-
- return dumpDoc(parsedDoc), nil
-}
-func (c *Context) Decrypt(doc []byte) ([]byte, error) {
- if err := c.init(); err != nil {
- return nil, err
- }
-
- return nil, nil
-}
-
-/*
+// Key is a PEM-encoded RSA private key, or a binary TDES key or a
+// binary AES key, depending on the encryption type in use.
func Decrypt(key []byte, doc []byte) ([]byte, error) {
+ out := bytes.NewBuffer(nil)
+ encoder := xml.NewEncoder(out)
+ decoder := xml.NewDecoder(bytes.NewReader(doc))
+ for {
+ t, err := decoder.Token()
+ if err == io.EOF {
+ break
+ } else if err != nil {
+ return nil, err
+ }
- parsedDoc, err := newDoc(doc)
- if err != nil {
- return nil, err
- }
- defer closeDoc(parsedDoc)
+ if startElement, ok := t.(xml.StartElement); ok {
+ if startElement.Name.Space == "http://www.w3.org/2001/04/xmlenc#" && startElement.Name.Local == "EncryptedData" {
+ d := encryptedData{}
+ if err := decoder.DecodeElement(&d, &startElement); err != nil {
+ return nil, err
+ }
- node := C.xmlSecFindNode(C.xmlDocGetRootElement(parsedDoc),
- (*C.xmlChar)(unsafe.Pointer(&C.xmlSecNodeEncryptedKey)),
- (*C.xmlChar)(unsafe.Pointer(&C.xmlSecEncNs)))
- if node == nil {
- return nil, errors.New("cannot find start node")
- }
+ plaintext, err := decryptEncryptedData(key, &d)
+ if err != nil {
+ return nil, err
+ }
- ctx, err := newContext(key)
- if err != nil {
- return nil, err
- }
- defer closeContext(ctx)
+ encoder.Flush()
+ out.Write(plaintext)
+ continue
+ }
+ }
- ctx.mode = C.xmlEncCtxModeEncryptedKey
+ encoder.EncodeToken(t)
+ }
+ encoder.Flush()
- if rv := C.xmlSecEncCtxDecrypt(ctx, node); rv < 0 {
- return nil, errors.New("cannot decrypt")
- }
- if ctx.result == nil {
- return nil, errors.New("cannot decrypt")
- }
-
- ctx2 := C.xmlSecEncCtxCreate(nil)
- if ctx2 == nil {
- return nil, errors.New("failed to create signature context")
- }
-
- ctx2.encKey = C.xmlSecKeyReadMemory(C.MY_xmlSecKeyDataDesId(),
- C.xmlSecBufferGetData(ctx.result),
- C.xmlSecBufferGetSize(ctx.result))
- if ctx2.encKey == nil {
- return nil, errors.New("cannot load session key")
- }
- ctx2.mode = C.xmlEncCtxModeEncryptedData
-
- node2 := C.xmlSecFindNode(C.xmlDocGetRootElement(parsedDoc),
- (*C.xmlChar)(unsafe.Pointer(&C.xmlSecNodeEncryptedData)),
- (*C.xmlChar)(unsafe.Pointer(&C.xmlSecEncNs)))
- if node2 == nil {
- return nil, errors.New("cannot find start node")
- }
-
- if rv := C.xmlSecEncCtxDecrypt(ctx2, node2); rv < 0 {
- return nil, errors.New("cannot decrypt")
- }
- if ctx2.result == nil {
- return nil, errors.New("cannot decrypt")
- }
-
- log.Panic("%s", string(dumpDoc(parsedDoc)))
-
- // Apparently we can either have replaced the document or not, so if we
- // have return it with dump.
- if ctx2.resultReplaced != 0 {
- return dumpDoc(parsedDoc), nil
- } else {
- sz := C.xmlSecBufferGetSize(ctx2.result)
- buf := C.xmlSecBufferGetData(ctx2.result)
- rv := C.GoStringN((*C.char)(unsafe.Pointer(buf)), C.int(sz)) // TODO(ross): eliminate double copy
- return []byte(rv), nil
- }
+ return out.Bytes(), nil
}
-// x
-// x
-// x
-// x
-// x
-// x
-// x
-// x
-// x
-// x
-// x
-// x
-// x
-// x
-// x
-// x
-// x
-// x
-// x
-// x
-// x
-// x
-// x
-// x
-// x
-// x
-// x
-// x
-// x
-// x
-// x
-// x
-// x
-// x
-// x
-// x
-*/
+// decryptEncryptedData decrypts the EncryptedData element and returns the
+// plaintext.
+func decryptEncryptedData(key []byte, d *encryptedData) ([]byte, error) {
+ if d.KeyInfo.EncryptedKey != nil {
+ var err error
+ key, err = decryptEncryptedKey(key, d.KeyInfo.EncryptedKey)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ iv := []byte{}
+ ciphertext, err := base64.StdEncoding.DecodeString(d.CipherData.CipherValue)
+ if err != nil {
+ return nil, err
+ }
+
+ var blockCipher cipher.Block
+ switch d.EncryptionMethod.Algorithm {
+ case "http://www.w3.org/2001/04/xmlenc#tripledes-cbc":
+ blockCipher, err = des.NewTripleDESCipher(key)
+ if err != nil {
+ return nil, err
+ }
+ iv = ciphertext[:des.BlockSize]
+ ciphertext = ciphertext[des.BlockSize:]
+
+ case "http://www.w3.org/2001/04/xmlenc#aes128-cbc",
+ "http://www.w3.org/2001/04/xmlenc#aes192-cbc",
+ "http://www.w3.org/2001/04/xmlenc#aes256-cbc":
+ blockCipher, err = aes.NewCipher(key)
+ if err != nil {
+ return nil, err
+ }
+ iv = ciphertext[:aes.BlockSize]
+ ciphertext = ciphertext[aes.BlockSize:]
+
+ default:
+ return nil, fmt.Errorf("unsupported encryption method: %s", d.EncryptionMethod.Algorithm)
+ }
+
+ mode := cipher.NewCBCDecrypter(blockCipher, iv)
+ mode.CryptBlocks(ciphertext, ciphertext)
+
+ return ciphertext, nil
+}
+
+// decryptEncryptedKey returns the plaintext version of the EncryptedKey which is
+// encrypted using RSA-PKCS1v15 or RSA-OAEP-MGF1P and assuming the `key` is
+// a PEM-encoded RSA private key.
+func decryptEncryptedKey(key []byte, encryptedKey *encryptedKey) ([]byte, error) {
+ // All the supported encryption schemes are based on RSA, so `key` must be an
+ // RSA key. (c.f. http://www.w3.org/TR/2002/REC-xmlenc-core-20021210/Overview.html
+ // in the "Key Transport" section)
+ pemBlock, _ := pem.Decode(key)
+ if pemBlock == nil {
+ return nil, fmt.Errorf("Cannot parse key as PEM encoded RSA private key")
+ }
+ rsaPriv, err := x509.ParsePKCS1PrivateKey(pemBlock.Bytes)
+ if err != nil {
+ return nil, err
+ }
+
+ // The only supported/required algorithm is SHA1
+ // (c.f. http://www.w3.org/TR/2001/PR-xmldsig-core-20010820/ section "Algorithms")
+ //
+ // TODO(ross): if RSA-PKCS1v15 is used, do we need to specify the digest algorithm?
+ var hashFunc hash.Hash
+ switch encryptedKey.EncryptionMethod.DigestMethod.Algorithm {
+ case "http://www.w3.org/2000/09/xmldsig#sha1":
+ hashFunc = sha1.New()
+ default:
+ return nil, fmt.Errorf("unsupported digest method: %s",
+ encryptedKey.EncryptionMethod.DigestMethod.Algorithm)
+ }
+
+ sessionKeyCiphertext, err := base64.StdEncoding.DecodeString(encryptedKey.CipherData.CipherValue)
+ if err != nil {
+ return nil, err
+ }
+
+ var sessionKeyPlaintext []byte
+ switch encryptedKey.EncryptionMethod.Algorithm {
+ case "http://www.w3.org/2001/04/xmlenc#rsa-1_5":
+ sessionKeyPlaintext, err = rsa.DecryptPKCS1v15(rand.Reader, rsaPriv,
+ sessionKeyCiphertext)
+ if err != nil {
+ return nil, err
+ }
+ case "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p":
+ sessionKeyPlaintext, err = rsa.DecryptOAEP(hashFunc, rand.Reader,
+ rsaPriv, sessionKeyCiphertext, nil)
+ if err != nil {
+ return nil, err
+ }
+ default:
+ return nil, fmt.Errorf("unsupported encryption method: %s",
+ encryptedKey.EncryptionMethod.Algorithm)
+ }
+
+ return sessionKeyPlaintext, nil
+}
diff --git a/xmlenc/xmlenc_test.go b/xmlenc/xmlenc_test.go
index c600333..83d7c15 100644
--- a/xmlenc/xmlenc_test.go
+++ b/xmlenc/xmlenc_test.go
@@ -1,98 +1,46 @@
package xmlenc
-import (
- "log"
- "testing"
+import "testing"
- . "gopkg.in/check.v1"
-)
-
-// Hook up gocheck into the "go test" runner.
-func Test(t *testing.T) { TestingT(t) }
-
-type EncryptTest struct{}
-
-var _ = Suite(&EncryptTest{})
-
-func (s *EncryptTest) TestEncrypt(c *C) {
+func TestDecrypt(t *testing.T) {
key := []byte(`-----BEGIN RSA PRIVATE KEY-----
-MIICXgIBAAKBgQDivbhR7P516x/S3BqKxupQe0LONoliupiBOesCO3SHbDrl3+q9
-IbfnfmE04rNuMcPsIxB161TdDpIesLCn7c8aPHISKOtPlAeTZSnb8QAu7aRjZq3+
-PbrP5uW3TcfCGPtKTytHOge/OlJbo078dVhXQ14d1EDwXJW1rRXuUt4C8QIDAQAB
-AoGAD4/Z4LWVWV6D1qMIp1Gzr0ZmdWTE1SPdZ7Ej8glGnCzPdguCPuzbhGXmIg0V
-J5D+02wsqws1zd48JSMXXM8zkYZVwQYIPUsNn5FetQpwxDIMPmhHg+QNBgwOnk8J
-K2sIjjLPL7qY7Itv7LT7Gvm5qSOkZ33RCgXcgz+okEIQMYkCQQDzbTOyDL0c5WQV
-6A2k06T/azdhUdGXF9C0+WkWSfNaovmTgRXh1G+jMlr82Snz4p4/STt7P/XtyWzF
-3pkVgZr3AkEA7nPjXwHlttNEMo6AtxHd47nizK2NUN803ElIUT8P9KSCoERmSXq6
-6PDekGNic4ldpsSvOeYCk8MAYoDBy9kvVwJBAMLgX4xg6lzhv7hR5+pWjTb1rIY6
-rCHbrPfU264+UZXz9v2BT/VUznLF81WMvStD9xAPHpFS6R0OLghSZhdzhI0CQQDL
-8Duvfxzrn4b9QlmduV8wLERoT6rEVxKLsPVz316TGrxJvBZLk/cV0SRZE1cZf4uk
-XSWMfEcJ/0Zt+LdG1CqjAkEAqwLSglJ9Dy3HpgMz4vAAyZWzAxvyA1zW0no9GOLc
-PQnYaNUN/Fy2SYtETXTb0CQ9X1rt8ffkFP7ya+5TC83aMg==
------END RSA PRIVATE KEY-----`)
- log.Printf("%s", string(key))
- cert := []byte(`-----BEGIN CERTIFICATE-----
-MIICgTCCAeoCCQCbOlrWDdX7FTANBgkqhkiG9w0BAQUFADCBhDELMAkGA1UEBhMC
-Tk8xGDAWBgNVBAgTD0FuZHJlYXMgU29sYmVyZzEMMAoGA1UEBxMDRm9vMRAwDgYD
-VQQKEwdVTklORVRUMRgwFgYDVQQDEw9mZWlkZS5lcmxhbmcubm8xITAfBgkqhkiG
-9w0BCQEWEmFuZHJlYXNAdW5pbmV0dC5ubzAeFw0wNzA2MTUxMjAxMzVaFw0wNzA4
-MTQxMjAxMzVaMIGEMQswCQYDVQQGEwJOTzEYMBYGA1UECBMPQW5kcmVhcyBTb2xi
-ZXJnMQwwCgYDVQQHEwNGb28xEDAOBgNVBAoTB1VOSU5FVFQxGDAWBgNVBAMTD2Zl
-aWRlLmVybGFuZy5ubzEhMB8GCSqGSIb3DQEJARYSYW5kcmVhc0B1bmluZXR0Lm5v
-MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDivbhR7P516x/S3BqKxupQe0LO
-NoliupiBOesCO3SHbDrl3+q9IbfnfmE04rNuMcPsIxB161TdDpIesLCn7c8aPHIS
-KOtPlAeTZSnb8QAu7aRjZq3+PbrP5uW3TcfCGPtKTytHOge/OlJbo078dVhXQ14d
-1EDwXJW1rRXuUt4C8QIDAQABMA0GCSqGSIb3DQEBBQUAA4GBACDVfp86HObqY+e8
-BUoWQ9+VMQx1ASDohBjwOsg2WykUqRXF+dLfcUH9dWR63CtZIKFDbStNomPnQz7n
-bK+onygwBspVEbnHuUihZq3ZUdmumQqCw4Uvs/1Uvq3orOo/WJVhTyvLgFVK2Qar
-Q4/67OZfHd7R+POBXhophSMv1ZOo
------END CERTIFICATE-----`)
- log.Printf("%s", string(cert))
+MIICXgIBAAKBgQDU8wdiaFmPfTyRYuFlVPi866WrH/2JubkHzp89bBQopDaLXYxi
+3PTu3O6Q/KaKxMOFBqrInwqpv/omOGZ4ycQ51O9I+Yc7ybVlW94lTo2gpGf+Y/8E
+PsVbnZaFutRctJ4dVIp9aQ2TpLiGT0xX1OzBO/JEgq9GzDRf+B+eqSuglwIDAQAB
+AoGBAMuy1eN6cgFiCOgBsB3gVDdTKpww87Qk5ivjqEt28SmXO13A1KNVPS6oQ8SJ
+CT5Azc6X/BIAoJCURVL+LHdqebogKljhH/3yIel1kH19vr4E2kTM/tYH+qj8afUS
+JEmArUzsmmK8ccuNqBcllqdwCZjxL4CHDUmyRudFcHVX9oyhAkEA/OV1OkjM3CLU
+N3sqELdMmHq5QZCUihBmk3/N5OvGdqAFGBlEeewlepEVxkh7JnaNXAXrKHRVu/f/
+fbCQxH+qrwJBANeQERF97b9Sibp9xgolb749UWNlAdqmEpmlvmS202TdcaaT1msU
+4rRLiQN3X9O9mq4LZMSVethrQAdX1whawpkCQQDk1yGf7xZpMJ8F4U5sN+F4rLyM
+Rq8Sy8p2OBTwzCUXXK+fYeXjybsUUMr6VMYTRP2fQr/LKJIX+E5ZxvcIyFmDAkEA
+yfjNVUNVaIbQTzEbRlRvT6MqR+PTCefC072NF9aJWR93JimspGZMR7viY6IM4lrr
+vBkm0F5yXKaYtoiiDMzlOQJADqmEwXl0D72ZG/2KDg8b4QZEmC9i5gidpQwJXUc6
+hU+IVQoLxRq0fBib/36K9tcrrO5Ba4iEvDcNY+D8yGbUtA==
+-----END RSA PRIVATE KEY-----
+`)
- docStr := []byte(`
-
-
-
- Hello, World!
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-`)
+ // This is an actual encrypted SAML response we got from testshib.org
+ docStr := []byte(`https://idp.testshib.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
+`)
- ctx := Context{}
- err := ctx.AddCert(cert)
- c.Assert(err, IsNil)
+ expectedSignedString := "https://idp.testshib.org/idp/shibbolethhttps://idp.testshib.org/idp/shibbolethVwEKsGObmOM6y22Nstadwz1fq6dnQ2aDmERPMuEteds=gcROTzJ7HgTu/LQprki8v9J5y4et2np48hYspgmygZRvRawzxfQDgB0MBvDIBG78J5XSd401g7E999JUEh4JtSMAig1THbeWhyITGHU1Vpl2xAR5Ma0vCMLjVIleeuFHhStFBNqKirNfulfhEa7Q5THVGKrVsNuIaP/yc10Gf8AyHfCIOf/ZQGiU3Srp/pKZLXPkSKTEZIq5tAOl+pA0maFBvb4+EkMPB6E66HiXknHL9KdNh8bPcq+EkqjhtHWOy341F8W9iy6MJYGuO9ksxdiY6FK5SqmPHlgoJqXx7Et2vYME6opIgFYB6m1KW6kWgVcF0VyIzJbkXq3yTi0b5g==MIIEDjCCAvagAwIBAgIBADANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJVUzEVMBMGA1UECBMM\nUGVubnN5bHZhbmlhMRMwEQYDVQQHEwpQaXR0c2J1cmdoMREwDwYDVQQKEwhUZXN0U2hpYjEZMBcG\nA1UEAxMQaWRwLnRlc3RzaGliLm9yZzAeFw0wNjA4MzAyMTEyMjVaFw0xNjA4MjcyMTEyMjVaMGcx\nCzAJBgNVBAYTAlVTMRUwEwYDVQQIEwxQZW5uc3lsdmFuaWExEzARBgNVBAcTClBpdHRzYnVyZ2gx\nETAPBgNVBAoTCFRlc3RTaGliMRkwFwYDVQQDExBpZHAudGVzdHNoaWIub3JnMIIBIjANBgkqhkiG\n9w0BAQEFAAOCAQ8AMIIBCgKCAQEArYkCGuTmJp9eAOSGHwRJo1SNatB5ZOKqDM9ysg7CyVTDClcp\nu93gSP10nH4gkCZOlnESNgttg0r+MqL8tfJC6ybddEFB3YBo8PZajKSe3OQ01Ow3yT4I+Wdg1tsT\npSge9gEz7SrC07EkYmHuPtd71CHiUaCWDv+xVfUQX0aTNPFmDixzUjoYzbGDrtAyCqA8f9CN2txI\nfJnpHE6q6CmKcoLADS4UrNPlhHSzd614kR/JYiks0K4kbRqCQF0Dv0P5Di+rEfefC6glV8ysC8dB\n5/9nb0yh/ojRuJGmgMWHgWk6h0ihjihqiu4jACovUZ7vVOCgSE5Ipn7OIwqd93zp2wIDAQABo4HE\nMIHBMB0GA1UdDgQWBBSsBQ869nh83KqZr5jArr4/7b+QazCBkQYDVR0jBIGJMIGGgBSsBQ869nh8\n3KqZr5jArr4/7b+Qa6FrpGkwZzELMAkGA1UEBhMCVVMxFTATBgNVBAgTDFBlbm5zeWx2YW5pYTET\nMBEGA1UEBxMKUGl0dHNidXJnaDERMA8GA1UEChMIVGVzdFNoaWIxGTAXBgNVBAMTEGlkcC50ZXN0\nc2hpYi5vcmeCAQAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAjR29PhrCbk8qLN5M\nFfSVk98t3CT9jHZoYxd8QMRLI4j7iYQxXiGJTT1FXs1nd4Rha9un+LqTfeMMYqISdDDI6tv8iNpk\nOAvZZUosVkUo93pv1T0RPz35hcHHYq2yee59HJOco2bFlcsH8JBXRSRrJ3Q7Eut+z9uo80JdGNJ4\n/SJy5UorZ8KazGj16lfJhOBXldgrhppQBb0Nq6HKHguqmwRfJ+WkxemZXzhediAjGeka8nz8Jjwx\npUjAiSWYKLtJhGEaTqCYxCCX2Dw+dOTqUzHOZ7WKv4JXPK5G/Uhr8K/qhmFT2nIQi538n6rVYLeW\nj8Bbnl+ev0peYzxFyF5sQA==_5c425656721b41a6cfa4a9c96225e082https://15661444.ngrok.io/saml2/metadataurn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransportmyselfMemberStaffmyself@testshib.orgAnd IMember@testshib.orgStaff@testshib.orgMe Myselfurn:mace:dir:entitlement:common-lib-termsMe Myself And I8F+M9ovyaYNwCId0pVkVsnZYRDo=555-5555\x01\n"
+ actualSignedString, err := Decrypt(key, docStr)
+ if err != nil {
+ t.Errorf("decrypt: %s", err)
+ return
+ }
- err = ctx.AddKey(key)
- c.Assert(err, IsNil)
-
- actualEncryptedString, err := ctx.Encrypt(docStr, []byte("Hello, World!"))
- c.Assert(err, IsNil)
- log.Printf("%s", actualEncryptedString)
-
- // expectedEncryptedString := "XXX"
- //c.Assert(string(actualEncryptedString), Equals, expectedEncryptedString)
-
- plaintext, err := ctx.Decrypt(actualEncryptedString)
- c.Assert(err, IsNil)
- log.Printf("plaintext=%s", plaintext)
- //c.Assert(string(plaintext), Equals, "Hello, World!")
+ if string(actualSignedString) != expectedSignedString {
+ t.Errorf("decrypt: expected %q, got `%q`", expectedSignedString, string(actualSignedString))
+ return
+ }
}