func (c AesContentCipher) decrypt(cek, iv, ciphertxt, tag, aad []byte) (plaintext []byte, err error) { aead, err := c.AeadFetch(cek) if err != nil { debug.Printf("AeadFetch failed for %v: %s", cek, err) return nil, err } // Open may panic (argh!), so protect ourselves from that defer func() { if e := recover(); e != nil { switch e.(type) { case error: err = e.(error) case string: err = errors.New(e.(string)) default: err = fmt.Errorf("%s", e) } return } }() combined := make([]byte, len(ciphertxt)+len(tag)) copy(combined, ciphertxt) copy(combined[len(ciphertxt):], tag) debug.Printf("AesContentCipher.decrypt: combined = %x (%d)", combined, len(combined)) plaintext, err = aead.Open(nil, iv, combined, aad) return }
// Seal fulfills the crypto.AEAD interface func (c AesCbcHmac) Seal(dst, nonce, plaintext, data []byte) []byte { ctlen := len(plaintext) ciphertext := make([]byte, ctlen+c.Overhead())[:ctlen] copy(ciphertext, plaintext) ciphertext = padbuf.PadBuffer(ciphertext).Pad(c.blockCipher.BlockSize()) cbc := cipher.NewCBCEncrypter(c.blockCipher, nonce) cbc.CryptBlocks(ciphertext, ciphertext) authtag := c.ComputeAuthTag(data, nonce, ciphertext) retlen := len(dst) + len(ciphertext) + len(authtag) ret := ensureSize(dst, retlen) out := ret[len(dst):] n := copy(out, ciphertext) n += copy(out[n:], authtag) if debug.Enabled { debug.Printf("Seal: ciphertext = %x (%d)\n", ciphertext, len(ciphertext)) debug.Printf("Seal: authtag = %x (%d)\n", authtag, len(authtag)) debug.Printf("Seal: ret = %x (%d)\n", ret, len(ret)) } return ret }
func New(key []byte, f BlockCipherFunc) (*AesCbcHmac, error) { keysize := len(key) / 2 ikey := key[:keysize] ekey := key[keysize:] debug.Printf("New: cek (key) = %x (%d)\n", key, len(key)) debug.Printf("New: ikey = %x (%d)\n", ikey, len(ikey)) debug.Printf("New: ekey = %x (%d)\n", ekey, len(ekey)) bc, err := f(ekey) if err != nil { return nil, err } var hfunc func() hash.Hash switch keysize { case 16: hfunc = sha256.New case 24: hfunc = sha512.New384 case 32: hfunc = sha512.New default: return nil, errors.New("unsupported key size") } return &AesCbcHmac{ blockCipher: bc, hash: hfunc, integrityKey: ikey, keysize: keysize, tagsize: NonceSize, }, nil }
func parseCompact(buf []byte) (*Message, error) { debug.Printf("Parse(Compact): buf = '%s'", buf) parts := bytes.Split(buf, []byte{'.'}) if len(parts) != 5 { return nil, ErrInvalidCompactPartsCount } hdrbuf := buffer.Buffer{} if err := hdrbuf.Base64Decode(parts[0]); err != nil { return nil, err } debug.Printf("hdrbuf = %s", hdrbuf) hdr := NewHeader() if err := json.Unmarshal(hdrbuf, hdr); err != nil { return nil, err } // We need the protected header to contain the content encryption // algorithm. XXX probably other headers need to go there too protected := NewEncodedHeader() protected.ContentEncryption = hdr.ContentEncryption hdr.ContentEncryption = "" enckeybuf := buffer.Buffer{} if err := enckeybuf.Base64Decode(parts[1]); err != nil { return nil, err } ivbuf := buffer.Buffer{} if err := ivbuf.Base64Decode(parts[2]); err != nil { return nil, err } ctbuf := buffer.Buffer{} if err := ctbuf.Base64Decode(parts[3]); err != nil { return nil, err } tagbuf := buffer.Buffer{} if err := tagbuf.Base64Decode(parts[4]); err != nil { return nil, err } m := NewMessage() m.AuthenticatedData.SetBytes(hdrbuf.Bytes()) m.ProtectedHeader = protected m.Tag = tagbuf m.CipherText = ctbuf m.InitializationVector = ivbuf m.Recipients = []Recipient{ Recipient{ Header: hdr, EncryptedKey: enckeybuf, }, } return m, nil }
func (c GenericContentCrypt) Encrypt(cek, plaintext, aad []byte) ([]byte, []byte, []byte, error) { debug.Printf("ContentCrypt.Encrypt: cek = %x", cek) debug.Printf("ContentCrypt.Encrypt: ciphertext = %x", plaintext) debug.Printf("ContentCrypt.Encrypt: aad = %x", aad) iv, encrypted, tag, err := c.cipher.encrypt(cek, plaintext, aad) if err != nil { debug.Printf("cipher.encrypt failed") return nil, nil, nil, err } return iv, encrypted, tag, nil }
func doMessageVerify(alg jwa.SignatureAlgorithm, v payloadVerifier, m *Message) error { var err error payload, err := m.Payload.Base64Encode() if err != nil { return err } for _, sig := range m.Signatures { if sig.ProtectedHeader.Algorithm != alg { continue } var phbuf []byte if sig.ProtectedHeader.Source.Len() > 0 { phbuf, err = sig.ProtectedHeader.Source.Base64Encode() if err != nil { continue } } else { phbuf, err = sig.ProtectedHeader.Base64Encode() if err != nil { continue } } siv := append(append(phbuf, '.'), payload...) if debug.Enabled { debug.Printf("siv = '%s'", siv) } if err := v.payloadVerify(siv, sig.Signature.Bytes()); err != nil { if debug.Enabled { debug.Printf("Payload verify failed: %s", err) } continue } return nil } return errors.New("none of the signatures could be verified") }
func (d RSAOAEPKeyDecrypt) KeyDecrypt(enckey []byte) ([]byte, error) { debug.Printf("START OAEP.KeyDecrypt") var hash hash.Hash switch d.alg { case jwa.RSA_OAEP: hash = sha1.New() case jwa.RSA_OAEP_256: hash = sha256.New() default: return nil, errors.New("failed to generate key encrypter for RSA-OAEP: RSA_OAEP/RSA_OAEP_256 required") } return rsa.DecryptOAEP(hash, rand.Reader, d.privkey, enckey, []byte{}) }
// Open fulfills the crypto.AEAD interface func (c AesCbcHmac) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { if len(ciphertext) < c.keysize { return nil, errors.New("invalid ciphertext (too short)") } tagOffset := len(ciphertext) - c.tagsize if tagOffset%c.blockCipher.BlockSize() != 0 { return nil, fmt.Errorf( "invalid ciphertext (invalid length: %d %% %d != 0)", tagOffset, c.blockCipher.BlockSize(), ) } tag := ciphertext[tagOffset:] ciphertext = ciphertext[:tagOffset] expectedTag := c.ComputeAuthTag(data, nonce, ciphertext) if subtle.ConstantTimeCompare(expectedTag, tag) != 1 { if debug.Enabled { debug.Printf("provided tag = %x\n", tag) debug.Printf("expected tag = %x\n", expectedTag) } return nil, errors.New("invalid ciphertext (tag mismatch)") } cbc := cipher.NewCBCDecrypter(c.blockCipher, nonce) buf := make([]byte, tagOffset) cbc.CryptBlocks(buf, ciphertext) plaintext, err := padbuf.PadBuffer(buf).Unpad(c.blockCipher.BlockSize()) if err != nil { return nil, err } ret := ensureSize(dst, len(plaintext)) out := ret[len(dst):] copy(out, plaintext) return ret, nil }
// KeyDecrypt decryptes the encrypted key using RSA PKCS1v1.5 func (d RSAPKCS15KeyDecrypt) KeyDecrypt(enckey []byte) ([]byte, error) { if debug.Enabled { debug.Printf("START PKCS.KeyDecrypt") } // Hey, these notes and workarounds were stolen from go-jose defer func() { // DecryptPKCS1v15SessionKey sometimes panics on an invalid payload // because of an index out of bounds error, which we want to ignore. // This has been fixed in Go 1.3.1 (released 2014/08/13), the recover() // only exists for preventing crashes with unpatched versions. // See: https://groups.google.com/forum/#!topic/golang-dev/7ihX6Y6kx9k // See: https://code.google.com/p/go/source/detail?r=58ee390ff31602edb66af41ed10901ec95904d33 _ = recover() }() // Perform some input validation. expectedlen := d.privkey.PublicKey.N.BitLen() / 8 if expectedlen != len(enckey) { // Input size is incorrect, the encrypted payload should always match // the size of the public modulus (e.g. using a 2048 bit key will // produce 256 bytes of output). Reject this since it's invalid input. return nil, fmt.Errorf( "input size for key decrypt is incorrect (expected %d, got %d)", expectedlen, len(enckey), ) } var err error bk, err := d.generator.KeyGenerate() if err != nil { return nil, errors.New("failed to generate key") } cek := bk.Bytes() // When decrypting an RSA-PKCS1v1.5 payload, we must take precautions to // prevent chosen-ciphertext attacks as described in RFC 3218, "Preventing // the Million Message Attack on Cryptographic Message Syntax". We are // therefore deliberatly ignoring errors here. err = rsa.DecryptPKCS1v15SessionKey(rand.Reader, d.privkey, enckey, cek) if err != nil { return nil, err } return cek, nil }
func (c AesContentCipher) encrypt(cek, plaintext, aad []byte) (iv, ciphertext, tag []byte, err error) { var aead cipher.AEAD aead, err = c.AeadFetch(cek) if err != nil { if debug.Enabled { debug.Printf("AeadFetch failed: %s", err) } err = fmt.Errorf("failed to fetch AEAD: %s", err) return } // Seal may panic (argh!), so protect ourselves from that defer func() { if e := recover(); e != nil { switch e.(type) { case error: err = e.(error) case string: err = errors.New(e.(string)) default: err = fmt.Errorf("%s", e) } return } }() var bs ByteSource if c.NonceGenerator == nil { bs, err = NewRandomKeyGenerate(aead.NonceSize()).KeyGenerate() } else { bs, err = c.NonceGenerator.KeyGenerate() } if err != nil { return } iv = bs.Bytes() combined := aead.Seal(nil, iv, plaintext, aad) tagoffset := len(combined) - c.TagSize() if debug.Enabled { debug.Printf("tagsize = %d", c.TagSize()) } tag = combined[tagoffset:] ciphertext = make([]byte, tagoffset) copy(ciphertext, combined[:tagoffset]) if debug.Enabled { debug.Printf("encrypt: combined = %x (%d)\n", combined, len(combined)) debug.Printf("encrypt: ciphertext = %x (%d)\n", ciphertext, len(ciphertext)) debug.Printf("encrypt: tag = %x (%d)\n", tag, len(tag)) debug.Printf("finally ciphertext = %x\n", ciphertext) } return }
// parseCompact parses a JWS value serialized via compact serialization. func parseCompact(buf []byte) (*Message, error) { parts := bytes.Split(buf, []byte{'.'}) if len(parts) != 3 { return nil, ErrInvalidCompactPartsCount } enc := base64.RawURLEncoding hdrbuf, err := buffer.FromBase64(parts[0]) if err != nil { return nil, err } debug.Printf("hdrbuf = %s", hdrbuf.Bytes()) hdr := &EncodedHeader{Header: NewHeader()} if err := json.Unmarshal(hdrbuf.Bytes(), hdr.Header); err != nil { return nil, err } hdr.Source = hdrbuf payload, err := buffer.FromBase64(parts[1]) if err != nil { return nil, err } signature := make([]byte, enc.DecodedLen(len(parts[2]))) if _, err := enc.Decode(signature, parts[2]); err != nil { return nil, err } signature = bytes.TrimRight(signature, "\x00") s := NewSignature() s.Signature = signature s.ProtectedHeader = hdr m := &Message{ Payload: buffer.Buffer(payload), Signatures: []Signature{*s}, } return m, nil }
// PayloadSign generates a sign based on the Algorithm instance variable. // This fulfills the `PayloadSigner` interface func (s EcdsaSign) PayloadSign(payload []byte) ([]byte, error) { hash, err := ecdsaHashForAlg(s.SignatureAlgorithm()) if err != nil { return nil, err } privkey := s.PrivateKey if privkey == nil { return nil, errors.New("cannot proceed with Sign(): no private key available") } keysiz := hash.Size() curveBits := privkey.Curve.Params().BitSize if curveBits != keysiz*8 { return nil, errors.New("key size does not match curve bit size") } h := hash.New() h.Write(payload) signed := h.Sum(nil) if debug.Enabled { debug.Printf("payload = %s, signed -> %x", payload, signed) } r, v, err := ecdsa.Sign(rand.Reader, privkey, signed) if err != nil { return nil, err } out := make([]byte, keysiz*2) keys := [][]byte{r.Bytes(), v.Bytes()} for i, data := range keys { start := i * keysiz padlen := keysiz - len(data) copy(out[start+padlen:], data) } return out, nil }
func (v EcdsaVerify) PayloadVerify(payload, signature []byte) error { pubkey := v.pubkey hfunc := v.hash keysiz := hfunc.Size() if len(signature) != 2*keysiz { return ErrInvalidEcdsaSignatureSize } rv := (&big.Int{}).SetBytes(signature[:keysiz]) sv := (&big.Int{}).SetBytes(signature[keysiz:]) h := hfunc.New() h.Write(payload) signed := h.Sum(nil) debug.Printf("payload -> %s, signed -> %x", payload, signed) if !ecdsa.Verify(pubkey, signed, rv, sv) { return ErrInvalidSignature } return nil }
func (c AesCbcHmac) ComputeAuthTag(aad, nonce, ciphertext []byte) []byte { debug.Printf("ComputeAuthTag: aad = %x (%d)\n", aad, len(aad)) debug.Printf("ComputeAuthTag: ciphertext = %x (%d)\n", ciphertext, len(ciphertext)) debug.Printf("ComputeAuthTag: iv (nonce) = %x (%d)\n", nonce, len(nonce)) debug.Printf("ComputeAuthTag: integrity = %x (%d)\n", c.integrityKey, len(c.integrityKey)) buf := make([]byte, len(aad)+len(nonce)+len(ciphertext)+8) n := 0 n += copy(buf, aad) n += copy(buf[n:], nonce) n += copy(buf[n:], ciphertext) binary.BigEndian.PutUint64(buf[n:], uint64(len(aad)*8)) h := hmac.New(c.hash, c.integrityKey) h.Write(buf) s := h.Sum(nil) debug.Printf("ComputeAuthTag: buf = %x (%d)\n", buf, len(buf)) debug.Printf("ComputeAuthTag: computed = %x (%d)\n", s[:c.keysize], len(s[:c.keysize])) return s[:c.tagsize] }
// Encrypt takes the plaintext payload and encrypts it in JWE compact format. func Encrypt(payload []byte, keyalg jwa.KeyEncryptionAlgorithm, key interface{}, contentalg jwa.ContentEncryptionAlgorithm, compressalg jwa.CompressionAlgorithm) ([]byte, error) { contentcrypt, err := NewAesCrypt(contentalg) if err != nil { return nil, err } var keyenc KeyEncrypter var keysize int switch keyalg { case jwa.RSA1_5: pubkey, ok := key.(*rsa.PublicKey) if !ok { return nil, errors.New("invalid key: *rsa.PublicKey required") } keyenc, err = NewRSAPKCSKeyEncrypt(keyalg, pubkey) if err != nil { return nil, err } keysize = contentcrypt.KeySize() / 2 case jwa.RSA_OAEP, jwa.RSA_OAEP_256: pubkey, ok := key.(*rsa.PublicKey) if !ok { return nil, errors.New("invalid key: *rsa.PublicKey required") } keyenc, err = NewRSAOAEPKeyEncrypt(keyalg, pubkey) if err != nil { return nil, err } keysize = contentcrypt.KeySize() / 2 case jwa.A128KW, jwa.A192KW, jwa.A256KW: sharedkey, ok := key.([]byte) if !ok { return nil, errors.New("invalid key: []byte required") } keyenc, err = NewAesKeyWrap(keyalg, sharedkey) if err != nil { return nil, err } keysize = contentcrypt.KeySize() case jwa.ECDH_ES_A128KW, jwa.ECDH_ES_A192KW, jwa.ECDH_ES_A256KW: pubkey, ok := key.(*ecdsa.PublicKey) if !ok { return nil, errors.New("invalid key: *ecdsa.PublicKey required") } keyenc, err = NewEcdhesKeyWrapEncrypt(keyalg, pubkey) if err != nil { return nil, err } keysize = contentcrypt.KeySize() case jwa.ECDH_ES: fallthrough case jwa.A128GCMKW, jwa.A192GCMKW, jwa.A256GCMKW: fallthrough case jwa.PBES2_HS256_A128KW, jwa.PBES2_HS384_A192KW, jwa.PBES2_HS512_A256KW: fallthrough default: debug.Printf("Encrypt: unknown key encryption algorithm: %s", keyalg) return nil, ErrUnsupportedAlgorithm } enc := NewMultiEncrypt(contentcrypt, NewRandomKeyGenerate(keysize), keyenc) msg, err := enc.Encrypt(payload) if err != nil { debug.Printf("Encrypt: failed to encrypt: %s", err) return nil, err } return CompactSerialize{}.Serialize(msg) }
// Decrypt decrypts the message using the specified algorithm and key func (m *Message) Decrypt(alg jwa.KeyEncryptionAlgorithm, key interface{}) ([]byte, error) { var err error if len(m.Recipients) == 0 { return nil, errors.New("no recipients, can not proceed with decrypt") } enc := m.ProtectedHeader.ContentEncryption h := NewHeader() if err := h.Copy(m.ProtectedHeader.Header); err != nil { return nil, err } h, err = h.Merge(m.UnprotectedHeader) if err != nil { if debug.Enabled { debug.Printf("failed to merge unprotected header") } return nil, err } aad, err := m.AuthenticatedData.Base64Encode() if err != nil { return nil, err } ciphertext := m.CipherText.Bytes() iv := m.InitializationVector.Bytes() tag := m.Tag.Bytes() cipher, err := buildContentCipher(enc) if err != nil { return nil, fmt.Errorf("unsupported content cipher algorithm '%s'", enc) } keysize := cipher.KeySize() var plaintext []byte for _, recipient := range m.Recipients { if debug.Enabled { debug.Printf("Attempting to check if we can decode for recipient (alg = %s)", recipient.Header.Algorithm) } if recipient.Header.Algorithm != alg { continue } h2 := NewHeader() if err := h2.Copy(h); err != nil { if debug.Enabled { debug.Printf("failed to copy header: %s", err) } continue } h2, err := h2.Merge(recipient.Header) if err != nil { if debug.Enabled { debug.Printf("Failed to merge! %s", err) } continue } k, err := BuildKeyDecrypter(h2.Algorithm, h2, key, keysize) if err != nil { if debug.Enabled { debug.Printf("failed to create key decrypter: %s", err) } continue } cek, err := k.KeyDecrypt(recipient.EncryptedKey.Bytes()) if err != nil { if debug.Enabled { debug.Printf("failed to decrypt key: %s", err) } continue } plaintext, err = cipher.decrypt(cek, iv, ciphertext, tag, aad) if err == nil { break } if debug.Enabled { debug.Printf("DecryptMessage: failed to decrypt using %s: %s", h2.Algorithm, err) } // Keep looping because there might be another key with the same algo } if plaintext == nil { return nil, errors.New("failed to find matching recipient to decrypt key") } if h.Compression == jwa.Deflate { output := bytes.Buffer{} w, _ := flate.NewWriter(&output, 1) in := plaintext for len(in) > 0 { n, err := w.Write(in) if err != nil { return nil, err } in = in[n:] } if err := w.Close(); err != nil { return nil, err } plaintext = output.Bytes() } return plaintext, nil }
"github.com/lestrrat/go-jwx/jwa" "github.com/lestrrat/go-jwx/jwe/aescbc" ) const ( TagSize = 16 ) func (f AeadFetchFunc) AeadFetch(key []byte) (cipher.AEAD, error) { return f(key) } var GcmAeadFetch = AeadFetchFunc(func(key []byte) (cipher.AEAD, error) { aescipher, err := aes.NewCipher(key) if err != nil { debug.Printf("GcmAeadFetch: failed to create cipher") return nil, fmt.Errorf("cipher: failed to create AES cipher for GCM: %s", err) } return cipher.NewGCM(aescipher) }) var CbcAeadFetch = AeadFetchFunc(func(key []byte) (cipher.AEAD, error) { aead, err := aescbc.New(key, aes.NewCipher) if err != nil { debug.Printf("CbcAeadFetch: failed to create aead fetcher (%v): %s", key, err) return nil, fmt.Errorf("cipher: failed to create AES cipher for CBC: %s", err) } return aead, nil }) func (c AesContentCipher) KeySize() int {
// Encrypt takes the plaintext and encrypts into a JWE message. func (e MultiEncrypt) Encrypt(plaintext []byte) (*Message, error) { bk, err := e.KeyGenerator.KeyGenerate() if err != nil { debug.Printf("Failed to generate key: %s", err) return nil, err } cek := bk.Bytes() debug.Printf("Encrypt: generated cek len = %d", len(cek)) protected := NewEncodedHeader() protected.Set("enc", e.ContentEncrypter.Algorithm()) // In JWE, multiple recipients may exist -- they receive an // encrypted version of the CEK, using their key encryption // algorithm of choice. recipients := make([]Recipient, len(e.KeyEncrypters)) for i, enc := range e.KeyEncrypters { r := NewRecipient() r.Header.Set("alg", enc.Algorithm()) if v := enc.Kid(); v != "" { r.Header.Set("kid", v) } enckey, err := enc.KeyEncrypt(cek) if err != nil { debug.Printf("Failed to encrypt key: %s", err) return nil, err } r.EncryptedKey = enckey.Bytes() if hp, ok := enckey.(HeaderPopulater); ok { hp.HeaderPopulate(r.Header) } debug.Printf("Encrypt: encrypted_key = %x (%d)", enckey.Bytes(), len(enckey.Bytes())) recipients[i] = *r } // If there's only one recipient, you want to include that in the // protected header if len(recipients) == 1 { protected.Header, err = protected.Header.Merge(recipients[0].Header) if err != nil { return nil, err } } aad, err := protected.Base64Encode() if err != nil { return nil, err } // ...on the other hand, there's only one content cipher. iv, ciphertext, tag, err := e.ContentEncrypter.Encrypt(cek, plaintext, aad) if err != nil { debug.Printf("Failed to encrypt: %s", err) return nil, err } debug.Printf("Encrypt.Encrypt: cek = %x (%d)", cek, len(cek)) debug.Printf("Encrypt.Encrypt: aad = %x", aad) debug.Printf("Encrypt.Encrypt: ciphertext = %x", ciphertext) debug.Printf("Encrypt.Encrypt: iv = %x", iv) debug.Printf("Encrypt.Encrypt: tag = %x", tag) msg := NewMessage() msg.AuthenticatedData.Base64Decode(aad) msg.CipherText = ciphertext msg.InitializationVector = iv msg.ProtectedHeader = protected msg.Recipients = recipients msg.Tag = tag return msg, nil }