From 42b4c03513bf5ca937e094fb0aabb7ad98100436 Mon Sep 17 00:00:00 2001 From: Daisuke Maki Date: Mon, 16 Nov 2015 07:22:18 +0900 Subject: [PATCH] Implement jwe.Encrypt/jwe.Decrypt --- internal/debug/debug_on.go | 9 ++- jwa/interface.go | 7 +- jwe/aescbc/aescbc.go | 6 +- jwe/cipher.go | 1 + jwe/doc_test.go | 8 +- jwe/encrypt.go | 6 ++ jwe/interface.go | 9 ++- jwe/jwe.go | 91 +++++++++++++++++----- jwe/jwe_test.go | 150 +++++++++++++------------------------ jwe/key_encrypt.go | 56 +++++++++++--- 10 files changed, 209 insertions(+), 134 deletions(-) diff --git a/internal/debug/debug_on.go b/internal/debug/debug_on.go index 9a46f30f3..467a7c318 100644 --- a/internal/debug/debug_on.go +++ b/internal/debug/debug_on.go @@ -2,8 +2,13 @@ package debug -import "log" +import ( + "log" + "os" +) + +var logger = log.New(os.Stdout, "|DEBUG| ", 0) func Printf(f string, args ...interface{}) { - log.Printf(f, args...) + logger.Printf(f, args...) } diff --git a/jwa/interface.go b/jwa/interface.go index 847beb3b8..1125617cf 100644 --- a/jwa/interface.go +++ b/jwa/interface.go @@ -5,7 +5,7 @@ type KeyType string const ( EC KeyType = "EC" // Elliptic Curve RSA KeyType = "RSA" // RSA - OctetSeq KeyType = "oct" // Octet sequence (used to represent symmetric keys) + OctetSeq KeyType = "oct" // Octet sequence (used to represent symmetric keys) ) type EllipticCurveAlgorithm string @@ -63,6 +63,7 @@ const ( // ContentEncryptionAlgorithm represents the various encryption // algorithms as described in https://tools.ietf.org/html/rfc7518#section-5 type ContentEncryptionAlgorithm string + const ( A128CBC_HS256 ContentEncryptionAlgorithm = "A128CBC-HS256" // AES-CBC + HMAC-SHA256 (128) A192CBC_HS384 ContentEncryptionAlgorithm = "A192CBC-HS384" // AES-CBC + HMAC-SHA384 (192) @@ -77,6 +78,6 @@ const ( type CompressionAlgorithm string const ( - NoCompression CompressionAlgorithm = "" // No compression - Deflate CompressionAlgorithm = "DEF" // DEFLATE (RFC 1951) + NoCompress CompressionAlgorithm = "" // No compression + Deflate CompressionAlgorithm = "DEF" // DEFLATE (RFC 1951) ) diff --git a/jwe/aescbc/aescbc.go b/jwe/aescbc/aescbc.go index 219c7fb0f..01c9e2a6c 100644 --- a/jwe/aescbc/aescbc.go +++ b/jwe/aescbc/aescbc.go @@ -33,9 +33,9 @@ func New(key []byte, f BlockCipherFunc) (*AesCbcHmac, error) { ikey := key[:keysize] ekey := key[keysize:] - debug.Printf("New: cek (key) = %x\n", key) - debug.Printf("New: ikey = %x\n", ikey) - debug.Printf("New: ekey = %x\n", ekey) + 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 { diff --git a/jwe/cipher.go b/jwe/cipher.go index 2b4f2c9ea..c113e2eed 100644 --- a/jwe/cipher.go +++ b/jwe/cipher.go @@ -24,6 +24,7 @@ var GcmAeadFetch = AeadFetchFunc(func(key []byte) (cipher.AEAD, error) { aescipher, err := aes.NewCipher(key) if err != nil { debug.Printf("GcmAeadFetch: failed to create cipher") + panic(err) return nil, err } diff --git a/jwe/doc_test.go b/jwe/doc_test.go index 82d1cc37a..f9c2fd44a 100644 --- a/jwe/doc_test.go +++ b/jwe/doc_test.go @@ -21,7 +21,11 @@ func ExampleEncrypt() { return } - k := NewRSAKeyEncrypt(jwa.RSA1_5, &privkey.PublicKey) + k, err := NewRSAPKCSKeyEncrypt(jwa.RSA1_5, &privkey.PublicKey) + if err != nil { + log.Printf("failed to create key encrypter: %s", err) + return + } kg := NewRandomKeyGenerate(c.KeySize()) e := NewMultiEncrypt(c, kg, k) @@ -31,7 +35,7 @@ func ExampleEncrypt() { return } - decrypted, err := DecryptMessage(msg, privkey) + decrypted, err := DecryptMessage(msg, jwa.RSA1_5, privkey) if err != nil { log.Printf("failed to decrypt: %s", err) return diff --git a/jwe/encrypt.go b/jwe/encrypt.go index 4c61e8a56..3cea98c18 100644 --- a/jwe/encrypt.go +++ b/jwe/encrypt.go @@ -18,6 +18,7 @@ func NewMultiEncrypt(cc ContentEncrypter, kg KeyGenerator, ke ...KeyEncrypter) * func (e MultiEncrypt) Encrypt(plaintext []byte) (*Message, error) { cek, err := e.KeyGenerator.KeyGenerate() if err != nil { + debug.Printf("Failed to generate key: %s", err) return nil, err } debug.Printf("Encrypt: generated cek len = %d", len(cek)) @@ -37,6 +38,7 @@ func (e MultiEncrypt) Encrypt(plaintext []byte) (*Message, error) { } enckey, err := enc.KeyEncrypt(cek) if err != nil { + debug.Printf("Failed to encrypt key: %s", err) return nil, err } r.EncryptedKey = enckey @@ -57,6 +59,10 @@ func (e MultiEncrypt) Encrypt(plaintext []byte) (*Message, error) { // ...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) diff --git a/jwe/interface.go b/jwe/interface.go index 6731c2c3a..2350ad2ea 100644 --- a/jwe/interface.go +++ b/jwe/interface.go @@ -188,8 +188,15 @@ type RSAPKCS15KeyDecrypt struct { generator KeyGenerator } -type RSAKeyEncrypt struct { +type RSAOAEPKeyEncrypt struct { alg jwa.KeyEncryptionAlgorithm pubkey *rsa.PublicKey KeyID string } + +type RSAPKCSKeyEncrypt struct { + alg jwa.KeyEncryptionAlgorithm + pubkey *rsa.PublicKey + KeyID string +} + diff --git a/jwe/jwe.go b/jwe/jwe.go index c0cb63149..4fa87fd78 100644 --- a/jwe/jwe.go +++ b/jwe/jwe.go @@ -16,24 +16,44 @@ import ( ) 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, jwa.RSA_OAEP, jwa.RSA_OAEP_256: + case jwa.RSA1_5: pubkey, ok := key.(*rsa.PublicKey) if !ok { return nil, errors.New("invalid key: *rsa.PublicKey required") } - keyenc = NewRSAKeyEncrypt(keyalg, pubkey) + 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") } - kwenc, err := NewAesKeyWrap(keyalg, sharedkey) + keyenc, err = NewAesKeyWrap(keyalg, sharedkey) if err != nil { return nil, err } - keyenc = kwenc + keysize = contentcrypt.KeySize() case jwa.ECDH_ES, jwa.ECDH_ES_A128KW, jwa.ECDH_ES_A192KW, jwa.ECDH_ES_A256KW: fallthrough case jwa.A128GCMKW, jwa.A192GCMKW, jwa.A256GCMKW: @@ -41,20 +61,57 @@ func Encrypt(payload []byte, keyalg jwa.KeyEncryptionAlgorithm, key interface{}, 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 } - contentcrypt, err := NewAesCrypt(contentalg) + 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 } - enc := NewMultiEncrypt(contentcrypt, NewRandomKeyGenerate(contentcrypt.KeySize()), keyenc) - msg, err := enc.Encrypt(payload) + + return CompactSerialize{}.Serialize(msg) +} + +func Decrypt(buf []byte, alg jwa.KeyEncryptionAlgorithm, key interface{}) ([]byte, error) { +/* + var keydec KeyEncrypter + switch keyalg { + case jwa.RSA1_5, jwa.RSA_OAEP, jwa.RSA_OAEP_256: + pubkey, ok := key.(*rsa.PrivateKey) + if !ok { + return nil, errors.New("invalid key: *rsa.PrivateKey required") + } + keydec = NewRSAKeyDecrypt(keyalg, pubkey) + case jwa.A128KW, jwa.A192KW, jwa.A256KW: + sharedkey, ok := key.([]byte) + if !ok { + return nil, errors.New("invalid key: []byte required") + } + kwenc, err := NewAesKeyWrap(keyalg, sharedkey) + if err != nil { + return nil, err + } + keydec = kwenc + case jwa.ECDH_ES, jwa.ECDH_ES_A128KW, jwa.ECDH_ES_A192KW, jwa.ECDH_ES_A256KW: + fallthrough + case jwa.A128GCMKW, jwa.A192GCMKW, jwa.A256GCMKW: + fallthrough + case jwa.PBES2_HS256_A128KW, jwa.PBES2_HS384_A192KW, jwa.PBES2_HS512_A256KW: + fallthrough + default: + return nil, ErrUnsupportedAlgorithm + } +*/ + + msg, err := Parse(buf) if err != nil { return nil, err } - return CompactSerialize{}.Serialize(msg) + return DecryptMessage(msg, alg, key) } func Parse(buf []byte) (*Message, error) { @@ -187,13 +244,13 @@ func BuildKeyDecrypter(alg jwa.KeyEncryptionAlgorithm, key interface{}, keysize if !ok { return nil, errors.New("*rsa.PrivateKey is required as the key to build this key decrypter") } - return NewRSAPKCS15KeyDecrypt(alg, privkey, keysize), nil + return NewRSAPKCS15KeyDecrypt(alg, privkey, keysize/2), nil case jwa.RSA_OAEP, jwa.RSA_OAEP_256: privkey, ok := key.(*rsa.PrivateKey) if !ok { return nil, errors.New("*rsa.PrivateKey is required as the key to build this key decrypter") } - return NewRSAOAEPKeyDecrypt(alg, privkey), nil + return NewRSAOAEPKeyDecrypt(alg, privkey) case jwa.A128KW, jwa.A192KW, jwa.A256KW: sharedkey, ok := key.([]byte) if !ok { @@ -214,7 +271,7 @@ func BuildContentCipher(alg jwa.ContentEncryptionAlgorithm) (ContentCipher, erro return nil, ErrUnsupportedAlgorithm } -func DecryptMessage(m *Message, key interface{}) ([]byte, error) { +func DecryptMessage(m *Message, alg jwa.KeyEncryptionAlgorithm, key interface{}) ([]byte, error) { var err error if len(m.Recipients) == 0 { @@ -258,6 +315,10 @@ func DecryptMessage(m *Message, key interface{}) ([]byte, error) { var plaintext []byte for _, recipient := range m.Recipients { + if recipient.Header.Algorithm != alg { + continue + } + h2 := NewHeader() if err := h2.Copy(h); err != nil { debug.Printf("failed to copy header: %s", err) @@ -280,19 +341,15 @@ func DecryptMessage(m *Message, key interface{}) ([]byte, error) { cek, err := k.KeyDecrypt(recipient.EncryptedKey.Bytes()) if err != nil { debug.Printf("failed to decrypt key: %s", err) + return nil, errors.New("failed to decrypt key") continue } - debug.Printf("DecryptMessage: cek = %x (%d)", cek, len(cek)) - debug.Printf("DecryptMessage: iv = %x", iv) - debug.Printf("DecryptMessage: ciphertext = %x", ciphertext) - debug.Printf("DecryptMessage: tag = %x", tag) - debug.Printf("DecryptMessage: aad = %x", aad) plaintext, err = cipher.decrypt(cek, iv, ciphertext, tag, aad) if err == nil { break } - debug.Printf("DecryptMessage: cipher.decrypt: %s", err) + debug.Printf("DecryptMessage: failed to decrypt using %s: %s", h2.Algorithm, err) } if plaintext == nil { diff --git a/jwe/jwe_test.go b/jwe/jwe_test.go index 32ea12236..24300b761 100644 --- a/jwe/jwe_test.go +++ b/jwe/jwe_test.go @@ -1,6 +1,7 @@ package jwe import ( + "crypto/rsa" "testing" "github.com/lestrrat/go-jwx/internal/rsautil" @@ -10,6 +11,28 @@ import ( const examplePayload = `The true sign of intelligence is not knowledge but imagination.` +var rsaPrivKey *rsa.PrivateKey + +func init() { + var jwkstr = []byte(` + {"kty":"RSA", + "n":"oahUIoWw0K0usKNuOR6H4wkf4oBUXHTxRvgb48E-BVvxkeDNjbC4he8rUWcJoZmds2h7M70imEVhRU5djINXtqllXI4DFqcI1DgjT9LewND8MW2Krf3Spsk_ZkoFnilakGygTwpZ3uesH-PFABNIUYpOiN15dsQRkgr0vEhxN92i2asbOenSZeyaxziK72UwxrrKoExv6kc5twXTq4h-QChLOln0_mtUZwfsRaMStPs6mS6XrgxnxbWhojf663tuEQueGC-FCMfra36C9knDFGzKsNa7LZK2djYgyD3JR_MB_4NUJW_TqOQtwHYbxevoJArm-L5StowjzGy-_bq6Gw", + "e":"AQAB", + "d":"kLdtIj6GbDks_ApCSTYQtelcNttlKiOyPzMrXHeI-yk1F7-kpDxY4-WY5NWV5KntaEeXS1j82E375xxhWMHXyvjYecPT9fpwR_M9gV8n9Hrh2anTpTD93Dt62ypW3yDsJzBnTnrYu1iwWRgBKrEYY46qAZIrA2xAwnm2X7uGR1hghkqDp0Vqj3kbSCz1XyfCs6_LehBwtxHIyh8Ripy40p24moOAbgxVw3rxT_vlt3UVe4WO3JkJOzlpUf-KTVI2Ptgm-dARxTEtE-id-4OJr0h-K-VFs3VSndVTIznSxfyrj8ILL6MG_Uv8YAu7VILSB3lOW085-4qE3DzgrTjgyQ", + "p":"1r52Xk46c-LsfB5P442p7atdPUrxQSy4mti_tZI3Mgf2EuFVbUoDBvaRQ-SWxkbkmoEzL7JXroSBjSrK3YIQgYdMgyAEPTPjXv_hI2_1eTSPVZfzL0lffNn03IXqWF5MDFuoUYE0hzb2vhrlN_rKrbfDIwUbTrjjgieRbwC6Cl0", + "q":"wLb35x7hmQWZsWJmB_vle87ihgZ19S8lBEROLIsZG4ayZVe9Hi9gDVCOBmUDdaDYVTSNx_8Fyw1YYa9XGrGnDew00J28cRUoeBB_jKI1oma0Orv1T9aXIWxKwd4gvxFImOWr3QRL9KEBRzk2RatUBnmDZJTIAfwTs0g68UZHvtc", + "dp":"ZK-YwE7diUh0qR1tR7w8WHtolDx3MZ_OTowiFvgfeQ3SiresXjm9gZ5KLhMXvo-uz-KUJWDxS5pFQ_M0evdo1dKiRTjVw_x4NyqyXPM5nULPkcpU827rnpZzAJKpdhWAgqrXGKAECQH0Xt4taznjnd_zVpAmZZq60WPMBMfKcuE", + "dq":"Dq0gfgJ1DdFGXiLvQEZnuKEN0UUmsJBxkjydc3j4ZYdBiMRAy86x0vHCjywcMlYYg4yoC4YZa9hNVcsjqA3FeiL19rk8g6Qn29Tt0cj8qqyFpz9vNDBUfCAiJVeESOjJDZPYHdHY8v1b-o-Z2X5tvLx-TCekf7oxyeKDUqKWjis", + "qi":"VIMpMYbPf47dT1w_zDUXfPimsSegnMOA1zTaX7aGk_8urY6R8-ZW1FxU7AlWAyLWybqq6t16VFd7hQd0y6flUK4SlOydB61gwanOsXGOAOv82cHq0E3eL4HrtZkUuKvnPrMnsUUFlfUdybVzxyjz9JF_XyaY14ardLSjf4L_FNY" + }`) + + var err error + rsaPrivKey, err = rsautil.PrivateKeyFromJSON(jwkstr) + if err != nil { + panic(err) + } +} + func TestSanityCheck_JWEExamplePayload(t *testing.T) { expected := []byte{ 84, 104, 101, 32, 116, 114, 117, 101, 32, 115, 105, 103, 110, 32, @@ -176,7 +199,7 @@ func TestParse_RSAES_OAEP_AES_GCM(t *testing.T) { t.Logf("------ ParseString done") // Test decrypting? - plaintext, err := DecryptMessage(msg, privkey) + plaintext, err := DecryptMessage(msg, jwa.RSA_OAEP, privkey) if !assert.NoError(t, err, "Decrypt message succeeded") { return } @@ -195,10 +218,24 @@ func TestParse_RSAES_OAEP_AES_GCM(t *testing.T) { t.Logf("%s", jsonbuf) return } + + encrypted, err := Encrypt(plaintext, jwa.RSA_OAEP, &privkey.PublicKey, jwa.A256GCM, jwa.NoCompress) + if !assert.NoError(t, err, "jwe.Encrypt should succeed") { + return + } + + plaintext, err = Decrypt(encrypted, jwa.RSA_OAEP, privkey) + if !assert.NoError(t, err, "jwe.Decrypt should succeed") { + return + } + + if !assert.Equal(t, payload, string(plaintext), "jwe.Decrypt should produce the same plaintext") { + return + } } // https://tools.ietf.org/html/rfc7516#appendix-A.1. -func TestEncode_RSAES_OAEP_AES_GCM(t *testing.T) { +func TestRoundtrip_RSAES_OAEP_AES_GCM(t *testing.T) { var plaintext = []byte{ 84, 104, 101, 32, 116, 114, 117, 101, 32, 115, 105, 103, 110, 32, 111, 102, 32, 105, 110, 116, 101, 108, 108, 105, 103, 101, 110, 99, @@ -206,33 +243,18 @@ func TestEncode_RSAES_OAEP_AES_GCM(t *testing.T) { 101, 100, 103, 101, 32, 98, 117, 116, 32, 105, 109, 97, 103, 105, 110, 97, 116, 105, 111, 110, 46, } - var cek = []byte{ - 4, 211, 31, 197, 84, 157, 252, 254, 11, 100, 157, 250, 63, 170, 106, - 206, 107, 124, 212, 45, 111, 107, 9, 219, 200, 177, 0, 240, 143, 156, - 44, 207, - } - var aad = []byte{ - 101, 121, 74, 104, 98, 71, 99, 105, 79, 105, 74, 83, 85, 48, 69, - 116, 84, 48, 70, 70, 85, 67, 73, 115, 73, 109, 86, 117, 89, 121, 73, - 54, 73, 107, 69, 121, 78, 84, 90, 72, 81, 48, 48, 105, 102, 81, - } - c, err := NewAesCrypt(jwa.A256GCM) - if !assert.NoError(t, err, "NewCrypt successful") { + encrypted, err := Encrypt(plaintext, jwa.RSA_OAEP, &rsaPrivKey.PublicKey, jwa.A256GCM, jwa.NoCompress) + if !assert.NoError(t, err, "Encrypt should succeed") { return } - iv, ciphertext, tag, err := c.Encrypt(cek, plaintext, aad) - if !assert.NoError(t, err, "Failed to encrypt data") { + decrypted, err := Decrypt(encrypted, jwa.RSA_OAEP, rsaPrivKey) + if !assert.NoError(t, err, "Decrypt should succeed") { return } - data, err := c.Decrypt(cek, iv, ciphertext, tag, aad) - if !assert.NoError(t, err, "Decrypt successful") { - return - } - - if !assert.Equal(t, plaintext, data, "roundtrip gives us the same data") { + if !assert.Equal(t, plaintext, decrypted, "Decrypted content should match") { return } } @@ -242,75 +264,25 @@ func TestRoundtrip_RSA1_5_A128CBC_HS256(t *testing.T) { 76, 105, 118, 101, 32, 108, 111, 110, 103, 32, 97, 110, 100, 32, 112, 114, 111, 115, 112, 101, 114, 46, } - var jwksrc = []byte(`{"kty":"RSA", - "n":"sXchDaQebHnPiGvyDOAT4saGEUetSyo9MKLOoWFsueri23bOdgWp4Dy1WlUzewbgBHod5pcM9H95GQRV3JDXboIRROSBigeC5yjU1hGzHHyXss8UDprecbAYxknTcQkhslANGRUZmdTOQ5qTRsLAt6BTYuyvVRdhS8exSZEy_c4gs_7svlJJQ4H9_NxsiIoLwAEk7-Q3UXERGYw_75IDrGA84-lA_-Ct4eTlXHBIY2EaV7t7LjJaynVJCpkv4LKjTTAumiGUIuQhrNhZLuF_RJLqHpM2kgWFLU7-VTdL1VbC2tejvcI2BlMkEpk1BzBZI0KQB0GaDWFLN-aEAw3vRw", - "e":"AQAB", - "d":"VFCWOqXr8nvZNyaaJLXdnNPXZKRaWCjkU5Q2egQQpTBMwhprMzWzpR8Sxq1OPThh_J6MUD8Z35wky9b8eEO0pwNS8xlh1lOFRRBoNqDIKVOku0aZb-rynq8cxjDTLZQ6Fz7jSjR1Klop-YKaUHc9GsEofQqYruPhzSA-QgajZGPbE_0ZaVDJHfyd7UUBUKunFMScbflYAAOYJqVIVwaYR5zWEEceUjNnTNo_CVSj-VvXLO5VZfCUAVLgW4dpf1SrtZjSt34YLsRarSb127reG_DUwg9Ch-KyvjT1SkHgUWRVGcyly7uvVGRSDwsXypdrNinPA4jlhoNdizK2zF2CWQ", - "p":"9gY2w6I6S6L0juEKsbeDAwpd9WMfgqFoeA9vEyEUuk4kLwBKcoe1x4HG68ik918hdDSE9vDQSccA3xXHOAFOPJ8R9EeIAbTi1VwBYnbTp87X-xcPWlEPkrdoUKW60tgs1aNd_Nnc9LEVVPMS390zbFxt8TN_biaBgelNgbC95sM", - "q":"uKlCKvKv_ZJMVcdIs5vVSU_6cPtYI1ljWytExV_skstvRSNi9r66jdd9-yBhVfuG4shsp2j7rGnIio901RBeHo6TPKWVVykPu1iYhQXw1jIABfw-MVsN-3bQ76WLdt2SDxsHs7q7zPyUyHXmps7ycZ5c72wGkUwNOjYelmkiNS0", - "dp":"w0kZbV63cVRvVX6yk3C8cMxo2qCM4Y8nsq1lmMSYhG4EcL6FWbX5h9yuvngs4iLEFk6eALoUS4vIWEwcL4txw9LsWH_zKI-hwoReoP77cOdSL4AVcraHawlkpyd2TWjE5evgbhWtOxnZee3cXJBkAi64Ik6jZxbvk-RR3pEhnCs", - "dq":"o_8V14SezckO6CNLKs_btPdFiO9_kC1DsuUTd2LAfIIVeMZ7jn1Gus_Ff7B7IVx3p5KuBGOVF8L-qifLb6nQnLysgHDh132NDioZkhH7mI7hPG-PYE_odApKdnqECHWw0J-F0JWnUd6D2B_1TvF9mXA2Qx-iGYn8OVV1Bsmp6qU", - "qi":"eNho5yRBEBxhGBtQRww9QirZsB66TrfFReG_CcteI1aCneT0ELGhYlRlCtUkTRclIfuEPmNsNDPbLoLqqCVznFbvdB7x-Tl-m0l_eFTj2KiqwGqE9PZB9nNTwMVvH3VRRSLWACvPnSiwP8N5Usy-WRXS-V7TbpxIhvepTfE0NNo" - }`) - privkey, err := rsautil.PrivateKeyFromJSON(jwksrc) - if !assert.NoError(t, err, "PrivateKey created") { - return - } - - c, err := NewAesCrypt(jwa.A128CBC_HS256) - if !assert.NoError(t, err, "NewAesCrypt is successful") { - return - } - - k := NewRSAKeyEncrypt(jwa.RSA1_5, &privkey.PublicKey) - - kg := NewRandomKeyGenerate(c.KeySize()) - - t.Logf("Encrypt now") - e := NewMultiEncrypt(c, kg, k) - msg, err := e.Encrypt(plaintext) - if !assert.NoError(t, err, "Encrypt successful") { - return - } - - t.Logf("DecryptMessage now") - plaintext2, err := DecryptMessage(msg, privkey) - if !assert.NoError(t, err, "Decrypt message succeeded") { - return - } - - if !assert.Equal(t, plaintext, plaintext2, "Decrypted correct plaintext") { - return - } - t.Logf("compact serialize now") - jsonbuf, err := CompactSerialize{}.Serialize(msg) - if !assert.NoError(t, err, "Compact serialization successful") { + encrypted, err := Encrypt(plaintext, jwa.RSA1_5, &rsaPrivKey.PublicKey, jwa.A128CBC_HS256, jwa.NoCompress) + if !assert.NoError(t, err, "Encrypt is successful") { return } - t.Logf("compact serialization: %s", jsonbuf) - - t.Logf("parse compact serialize now") - msg2, err := Parse(jsonbuf) - if !assert.NoError(t, err, "Parse successful") { - return - } - - t.Logf("====== decrypt compact serialize now") - plaintext3, err := DecryptMessage(msg2, privkey) - if !assert.NoError(t, err, "Decrypt message succeeded") { + decrypted, err := Decrypt(encrypted, jwa.RSA1_5, rsaPrivKey) + if !assert.NoError(t, err, "Decrypt successful") { return } - if !assert.Equal(t, plaintext, plaintext3, "Roundtrip is successful!") { + if !assert.Equal(t, plaintext, decrypted, "Decrypted correct plaintext") { return } } // https://tools.ietf.org/html/rfc7516#appendix-A.3. Note that cek is dynamically // generated, so the encrypted values will NOT match that of the RFC. -func TestEncode_A128KW_A128CBCHS256(t *testing.T) { +func TestEncode_A128KW_A128CBC_HS256(t *testing.T) { var plaintext = []byte{ 76, 105, 118, 101, 32, 108, 111, 110, 103, 32, 97, 110, 100, 32, 112, 114, 111, 115, 112, 101, 114, 46, @@ -319,31 +291,17 @@ func TestEncode_A128KW_A128CBCHS256(t *testing.T) { 25, 172, 32, 130, 225, 114, 26, 181, 138, 106, 254, 192, 95, 133, 74, 82, } - c, err := NewAesCrypt(jwa.A128CBC_HS256) - if !assert.NoError(t, err, "NewAesCrypt is successful") { - return - } - - k, err := NewAesKeyWrap(jwa.A128KW, sharedkey) - if !assert.NoError(t, err, "Create key wrap") { - return - } - - kg := NewRandomKeyGenerate(c.KeySize()) - - e := NewMultiEncrypt(c, kg, k) - - msg, err := e.Encrypt(plaintext) - if !assert.NoError(t, err, "Encrypt successful") { + encrypted, err := Encrypt(plaintext, jwa.A128KW, sharedkey, jwa.A128CBC_HS256, jwa.NoCompress) + if !assert.NoError(t, err, "Encrypt is successful") { return } - data, err := DecryptMessage(msg, sharedkey) + decrypted, err := Decrypt(encrypted, jwa.A128KW, sharedkey) if !assert.NoError(t, err, "Decrypt successful") { return } - if !assert.Equal(t, plaintext, data, "roundtrip gives us the same data") { + if !assert.Equal(t, plaintext, decrypted, "Decrypted correct plaintext") { return } } diff --git a/jwe/key_encrypt.go b/jwe/key_encrypt.go index 6d348a37c..848fba019 100644 --- a/jwe/key_encrypt.go +++ b/jwe/key_encrypt.go @@ -57,27 +57,56 @@ func (kw KeyWrapEncrypt) KeyEncrypt(cek []byte) ([]byte, error) { return encrypted, nil } -func NewRSAKeyEncrypt(alg jwa.KeyEncryptionAlgorithm, pubkey *rsa.PublicKey) *RSAKeyEncrypt { - return &RSAKeyEncrypt{ +func NewRSAOAEPKeyEncrypt(alg jwa.KeyEncryptionAlgorithm, pubkey *rsa.PublicKey) (*RSAOAEPKeyEncrypt, error) { + switch alg { + case jwa.RSA_OAEP, jwa.RSA_OAEP_256: + default: + return nil, ErrUnsupportedAlgorithm + } + return &RSAOAEPKeyEncrypt{ alg: alg, pubkey: pubkey, + }, nil +} + +func NewRSAPKCSKeyEncrypt(alg jwa.KeyEncryptionAlgorithm, pubkey *rsa.PublicKey) (*RSAPKCSKeyEncrypt, error) { + switch alg { + case jwa.RSA1_5: + default: + return nil, ErrUnsupportedAlgorithm } + + return &RSAPKCSKeyEncrypt{ + alg: alg, + pubkey: pubkey, + }, nil +} + +func (e RSAPKCSKeyEncrypt) Algorithm() jwa.KeyEncryptionAlgorithm { + return e.alg } -func (e RSAKeyEncrypt) Algorithm() jwa.KeyEncryptionAlgorithm { +func (e RSAPKCSKeyEncrypt) Kid() string { + return e.KeyID +} + +func (e RSAOAEPKeyEncrypt) Algorithm() jwa.KeyEncryptionAlgorithm { return e.alg } -func (e RSAKeyEncrypt) Kid() string { +func (e RSAOAEPKeyEncrypt) Kid() string { return e.KeyID } -func (e RSAKeyEncrypt) KeyEncrypt(cek []byte) ([]byte, error) { - debug.Printf("RSA.KeyEncrypt: cek = %x", cek) - if e.alg == jwa.RSA1_5 { - return rsa.EncryptPKCS1v15(rand.Reader, e.pubkey, cek) +func (e RSAPKCSKeyEncrypt) KeyEncrypt(cek []byte) ([]byte, error) { + if e.alg != jwa.RSA1_5 { + debug.Printf("PKCS.KeyEncrypt: %s", e.alg) + return nil, ErrUnsupportedAlgorithm } + return rsa.EncryptPKCS1v15(rand.Reader, e.pubkey, cek) +} +func (e RSAOAEPKeyEncrypt) KeyEncrypt(cek []byte) ([]byte, error) { var hash hash.Hash switch e.alg { case jwa.RSA_OAEP: @@ -85,6 +114,7 @@ func (e RSAKeyEncrypt) KeyEncrypt(cek []byte) ([]byte, error) { case jwa.RSA_OAEP_256: hash = sha256.New() default: + debug.Printf("OAEP.KeyEncrypt: %s", e.alg) return nil, ErrUnsupportedAlgorithm } return rsa.EncryptOAEP(hash, rand.Reader, e.pubkey, cek, []byte{}) @@ -150,11 +180,17 @@ type RSAOAEPKeyDecrypt struct { privkey *rsa.PrivateKey } -func NewRSAOAEPKeyDecrypt(alg jwa.KeyEncryptionAlgorithm, privkey *rsa.PrivateKey) *RSAOAEPKeyDecrypt { +func NewRSAOAEPKeyDecrypt(alg jwa.KeyEncryptionAlgorithm, privkey *rsa.PrivateKey) (*RSAOAEPKeyDecrypt, error) { + switch alg { + case jwa.RSA_OAEP, jwa.RSA_OAEP_256: + default: + return nil, ErrUnsupportedAlgorithm + } + return &RSAOAEPKeyDecrypt{ alg: alg, privkey: privkey, - } + }, nil } func (d RSAOAEPKeyDecrypt) Algorithm() jwa.KeyEncryptionAlgorithm {