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 + } }