forked from crewjam/saml
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add pure-go partial implementation of xmlenc
This commit adds a (partial, but hopefully sufficient) implementation of the XML encryption standard, which along with a pure-go implementation of xmldsig will remove the requirement to depend on native libxmlsec. This commit includes a simple go-fuzz implementation which has found a few issues with the initial implementation.
- Loading branch information
Showing
49 changed files
with
2,345 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,3 +9,5 @@ addons: | |
go: | ||
- 1.6 | ||
- 1.7 | ||
- 1.8 | ||
- tip |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) (*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 | ||
} |
42 changes: 42 additions & 0 deletions
42
xmlenc/corpus/bad-encrypt-content-aes128-cbc-kw-aes192.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<PurchaseOrder xmlns="urn:example:po"> | ||
<Items> | ||
<Item Code="001-001-001" Quantity="1"> | ||
spade | ||
</Item> | ||
<Item Code="001-001-002" Quantity="1"> | ||
shovel | ||
</Item> | ||
</Items> | ||
<ShippingAddress> | ||
Dig PLC, 1 First Ave, Dublin 1, Ireland | ||
</ShippingAddress> | ||
<PaymentInfo> | ||
<EncryptedData xmlns="http://www.w3.org/2001/04/xmlenc#" Type="http://www.w3.org/2001/04/xmlenc#Content"> | ||
<EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc" /> | ||
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"> | ||
<EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#"> | ||
<EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#kw-aes192" /> | ||
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"> | ||
<KeyName>jeb</KeyName> | ||
</KeyInfo> | ||
<CipherData> | ||
<CipherValue> | ||
JbjZH7Mq564oMybpvCHWYM/5ER3eFsAV | ||
</CipherValue> | ||
</CipherData> | ||
</EncryptedKey> | ||
</KeyInfo> | ||
<CipherData> | ||
<CipherValue> | ||
YDYTxR+smxZDSVoXXEp3n6HzTgWqV7ZlG6I1lmEv7zLGZBF/o7eqe5QGT6L3DPNW | ||
geflA8vVJHxwliixWcvHCnNKQkx+Sw8YbIknCQyr4mqtXEmHhsie5XYTEyqgKLVP | ||
YdNXf56wLUTMEmBqq7cto9OrYcBWkrDcQQvHmDkHuG+Nom4m+623GsB0FNts6VyN | ||
sdGMwo4K0bEFReLL04l6It+cgLJ2q+LKdBoMQL59IAQmrwi0bkiqee2cLlDuGyQ1 | ||
KD9IQ1qtlJpvQujN4xNVWT00UjtWxmpSMID/Kue/AnXn7Cf8zw1ZZQitgh8uWOX2 | ||
uMy99F2YlxqIK1r+MeXHuZDNf75S8dFaKIKtHMf7ioA= | ||
</CipherValue> | ||
</CipherData> | ||
</EncryptedData> | ||
</PaymentInfo> | ||
</PurchaseOrder> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<PurchaseOrder xmlns="urn:example:po"> | ||
<Items> | ||
<Item Code="001-001-001" Quantity="1"> | ||
spade | ||
</Item> | ||
<Item Code="001-001-002" Quantity="1"> | ||
shovel | ||
</Item> | ||
</Items> | ||
<ShippingAddress> | ||
Dig PLC, 1 First Ave, Dublin 1, Ireland | ||
</ShippingAddress> | ||
<PaymentInfo> | ||
<EncryptedData xmlns="http://www.w3.org/2001/04/xmlenc#" Id="encrypt-data-0" Type="http://www.w3.org/2001/04/xmlenc#Content"> | ||
<EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc" /> | ||
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"> | ||
<KeyName>jed</KeyName> | ||
</KeyInfo> | ||
<CipherData> | ||
<CipherValue> | ||
cX6lnfgmvWuxyiQgNhzAq1lYggW2M5GziFgNBQju3xcnDqlzf5LSjeyBnbL0Q7ws | ||
8XhySFCrdwIi5mVxyfdFkVrTlzQQ0viaqTDgi9PQRgZMOImGGWij3wbmf9XseHHt | ||
6q8V7LPjMFQAnsLDQgKf4gzzOnhtKf15GfTEpGvUnNn2dLDxw+hDcD1N54/bjSQs | ||
uTiL7PgGQ5g4u4eaXRRLWeAGsIf5QgdQG3GLiOZIX1LJ5bREKgXeKrtJJI97xUX3 | ||
3vaF+tKRcSFBFIMjFrw271bFj4vvvQZfSS6xX+BKXHOUu8C4NH9Le8pA9o4NgCB8 | ||
tWA8W3iI5/BGEZve0Me9byvPHYjRXlbG+YqysVTmzfw= | ||
</CipherValue> | ||
</CipherData> | ||
</EncryptedData> | ||
<EncryptedData xmlns="http://www.w3.org/2001/04/xmlenc#" Id="encrypt-data-1"> | ||
<EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc" /> | ||
<CipherData> | ||
<CipherValue> | ||
x3aR5pJ5pepFFH5ENv61pZG4pVwNKaM+H9oyY4qG6d8l/C0J1iGv6c8dyLp0YQ2k | ||
</CipherValue> | ||
</CipherData> | ||
</EncryptedData> | ||
</PaymentInfo> | ||
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#"> | ||
<SignedInfo> | ||
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" /> | ||
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#dsa-sha1" /> | ||
<Reference URI=""> | ||
<Transforms> | ||
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /> | ||
<Transform Algorithm="http://www.w3.org/2001/04/decrypt#"> | ||
<Except xmlns="http://www.w3.org/2001/04/decrypt#" URI="#encrypt-data-1" /> | ||
</Transform> | ||
</Transforms> | ||
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" /> | ||
<DigestValue>5Oe9qba6preOZG1NZAYK2/6pu9RCon9vRJ9hVLDpeng=</DigestValue> | ||
</Reference> | ||
</SignedInfo> | ||
<SignatureValue> | ||
LuHrz9+WG7/c4Q81tFboNZg2cktWbZcRfp08XrmgKy1GDm9xSfTYCA== | ||
</SignatureValue> | ||
<KeyInfo> | ||
<KeyValue> | ||
<DSAKeyValue> | ||
<P> | ||
imup6lmki4rAmUstKb/xdBRMWNtQ+pDN97ZnLA9X3lKbkEHtYFyjQ3uActgVSJ75 | ||
iVRuKxz4Cb5RzVm25EaKmKq8rif1MtBIi6jjDJxmIdNaEKG9zVTf9giJx1N9I0t3 | ||
oh1fAVZDSrzKzJGQ2WvDfIfFHdJMtB3C0VKGmLZR7Xk= | ||
</P> | ||
<Q> | ||
xDve3j7sEnh4rIzM5gK+5/gxxFU= | ||
</Q> | ||
<G> | ||
NLugAf6IZJxo3BCOi5yrGEVwtlEzXcnndXhd0Tz38CnQKc4SEupm4PyP5TmLvK64 | ||
TDfOD7sno/W5oI1KZdimfW2c4r/6waNzZSvicMOWhLYY621Nn6njBc8VNwoxWpzC | ||
XhKm70b8+D4YZMn/eU5DN8dvhTv/bNK21FfJqjp033U= | ||
</G> | ||
<Y> | ||
W7dOmH/vWqocVCiqaxj6soxVXfR8XpMdY2Zv4Amjr3n81geyOLb6IZ+l7MUbdp85 | ||
29DQzuoVTthVpB9X4JKCprZIzifOTM1PFflTBzjx7egJwJWAIVdWyiIPjke6Va+w | ||
uV2n4Rl/cgCvrXK5cTov5C/Bpaf6o+qrrDGFBLLZTF4= | ||
</Y> | ||
</DSAKeyValue> | ||
</KeyValue> | ||
</KeyInfo> | ||
</Signature> | ||
</PurchaseOrder> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<PurchaseOrder xmlns="urn:example:po"> | ||
<Items> | ||
<Item Code="001-001-001" Quantity="1"> | ||
spade | ||
</Item> | ||
<Item Code="001-001-002" Quantity="1"> | ||
shovel | ||
</Item> | ||
</Items> | ||
<ShippingAddress> | ||
Dig PLC, 1 First Ave, Dublin 1, Ireland | ||
</ShippingAddress> | ||
<PaymentInfo> | ||
<EncryptedData xmlns="http://www.w3.org/2001/04/xmlenc#" Id="encrypt-data-0" Type="http://www.w3.org/2001/04/xmlenc#Content"> | ||
<EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc" /> | ||
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"> | ||
<KeyName>jed</KeyName> | ||
</KeyInfo> | ||
<CipherData> | ||
<CipherValue> | ||
SE3HkQevYxzuN9LoMH3QIYHK0X7DBlobhiTbRucgKcTKt9DsUJIcd6JZV6lrw/4x | ||
YICyq6YM73IWpibspxgz/0chhvWem9sYZvWTuTtZgHzeY0Uri6bpXqBEn1YT0K6B | ||
chwfv1myfp91EmdPHU+shH6ZEyYkHJUMss58iIawIuVsIfpCO7xDKgfs/glnN3os | ||
epY0KvAMZSnwUAf42fQ3TlahLTR+B52AmdodwaCwQlwQwrC7RH0FtNiiLQA9SA2t | ||
//StKWcyHjswUCejfKLdjv6bK+WmBxmnNWtmI9DYkjJ6V5pYU1MVw+JG410O+gaa | ||
fnNWxlWa+BGwcTaz+KNrP8bIqli8IoJJgxXIUqfb734= | ||
</CipherValue> | ||
</CipherData> | ||
</EncryptedData> | ||
</PaymentInfo> | ||
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#"> | ||
<SignedInfo> | ||
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" /> | ||
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#dsa-sha1" /> | ||
<Reference URI=""> | ||
<Transforms> | ||
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /> | ||
<Transform Algorithm="http://www.w3.org/2001/04/decrypt#" /> | ||
</Transforms> | ||
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" /> | ||
<DigestValue>wSvPYqTcpLfX2mKXibtsmm7FDu8N+/BObM0+bGaeXhk=</DigestValue> | ||
</Reference> | ||
</SignedInfo> | ||
<SignatureValue> | ||
O0VYUdslJ8t2EURD0T/v2nNrFQMo42vzvfAhooZrDbkuLbCj6/Hxmw== | ||
</SignatureValue> | ||
<KeyInfo> | ||
<KeyValue> | ||
<DSAKeyValue> | ||
<P> | ||
imup6lmki4rAmUstKb/xdBRMWNtQ+pDN97ZnLA9X3lKbkEHtYFyjQ3uActgVSJ75 | ||
iVRuKxz4Cb5RzVm25EaKmKq8rif1MtBIi6jjDJxmIdNaEKG9zVTf9giJx1N9I0t3 | ||
oh1fAVZDSrzKzJGQ2WvDfIfFHdJMtB3C0VKGmLZR7Xk= | ||
</P> | ||
<Q> | ||
xDve3j7sEnh4rIzM5gK+5/gxxFU= | ||
</Q> | ||
<G> | ||
NLugAf6IZJxo3BCOi5yrGEVwtlEzXcnndXhd0Tz38CnQKc4SEupm4PyP5TmLvK64 | ||
TDfOD7sno/W5oI1KZdimfW2c4r/6waNzZSvicMOWhLYY621Nn6njBc8VNwoxWpzC | ||
XhKm70b8+D4YZMn/eU5DN8dvhTv/bNK21FfJqjp033U= | ||
</G> | ||
<Y> | ||
W7dOmH/vWqocVCiqaxj6soxVXfR8XpMdY2Zv4Amjr3n81geyOLb6IZ+l7MUbdp85 | ||
29DQzuoVTthVpB9X4JKCprZIzifOTM1PFflTBzjx7egJwJWAIVdWyiIPjke6Va+w | ||
uV2n4Rl/cgCvrXK5cTov5C/Bpaf6o+qrrDGFBLLZTF4= | ||
</Y> | ||
</DSAKeyValue> | ||
</KeyValue> | ||
</KeyInfo> | ||
</Signature> | ||
</PurchaseOrder> |
Oops, something went wrong.