Skip to content
This repository has been archived by the owner on Aug 19, 2019. It is now read-only.

Commit

Permalink
cbc done
Browse files Browse the repository at this point in the history
  • Loading branch information
Guillaume Simonneau committed May 20, 2019
1 parent 5fd75b1 commit 9c76051
Show file tree
Hide file tree
Showing 6 changed files with 201 additions and 40 deletions.
20 changes: 10 additions & 10 deletions jwe.factory.cbc.go
@@ -1,17 +1,17 @@
package jwc

import (
"crypto"
"crypto/aes"
"crypto/cipher"
"crypto/rsa"
"crypto/sha256"
"crypto/sha512"
"encoding/base64"
"encoding/json"
"hash"
)

func newJWEA128CBCHS256(protectedHeaders *JOSEHeaders, pubKey *rsa.PublicKey, plaintext []byte) (*JWE, error) {
func newJWEA128CBCHS256(protectedHeaders *JOSEHeaders, pubKey crypto.PublicKey, plaintext []byte) (*JWE, error) {
cek, cipherCEK, cipherCEKB64, err := GenerateCEK(16, protectedHeaders.Algorithm, pubKey)
if err != nil {
return nil, err
Expand All @@ -20,15 +20,15 @@ func newJWEA128CBCHS256(protectedHeaders *JOSEHeaders, pubKey *rsa.PublicKey, pl
return newCBC(cek, cipherCEK, cipherCEKB64, hashAlg, protectedHeaders, pubKey, plaintext)
}

func newJWEA192CBCHS384(protectedHeaders *JOSEHeaders, pubKey *rsa.PublicKey, plaintext []byte) (*JWE, error) {
func newJWEA192CBCHS384(protectedHeaders *JOSEHeaders, pubKey crypto.PublicKey, plaintext []byte) (*JWE, error) {
cek, cipherCEK, cipherCEKB64, err := GenerateCEK(24, protectedHeaders.Algorithm, pubKey)
if err != nil {
return nil, err
}
hashAlg := sha512.New384()
return newCBC(cek, cipherCEK, cipherCEKB64, hashAlg, protectedHeaders, pubKey, plaintext)
}
func newJWEA256CBCHS512(protectedHeaders *JOSEHeaders, pubKey *rsa.PublicKey, plaintext []byte) (*JWE, error) {
func newJWEA256CBCHS512(protectedHeaders *JOSEHeaders, pubKey crypto.PublicKey, plaintext []byte) (*JWE, error) {
cek, cipherCEK, cipherCEKB64, err := GenerateCEK(32, protectedHeaders.Algorithm, pubKey)
if err != nil {
return nil, err
Expand All @@ -43,26 +43,26 @@ func newCBC(
cipherCEKB64 string,
hash hash.Hash,
protectedHeaders *JOSEHeaders,
pubKey *rsa.PublicKey,
pubKey crypto.PublicKey,
plaintext []byte,
) (*JWE, error) {
headersBytes, err := json.Marshal(protectedHeaders)
if err != nil {
return nil, err
}
headersB64 := base64.RawURLEncoding.EncodeToString(headersBytes)
iv, ivB64, err := GenerateInitVector(aes.BlockSize)
block, err := aes.NewCipher(cek)
if err != nil {
return nil, err
}
ciphertext := make([]byte, 0, aes.BlockSize+len(plaintext))
ciphertext = append(ciphertext, iv...)
block, err := aes.NewCipher(cek)
iv, ivB64, err := GenerateInitVector(aes.BlockSize)
if err != nil {
return nil, err
}
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(ciphertext[aes.BlockSize:], plaintext)
plaintext = Pad(plaintext, aes.BlockSize)
ciphertext := make([]byte, len(plaintext))
mode.CryptBlocks(ciphertext, plaintext)
ciphertextB64 := base64.RawURLEncoding.EncodeToString(ciphertext)
jwe := JWE{
ProtectedB64: headersB64,
Expand Down
10 changes: 5 additions & 5 deletions jwe.factory.gcm.go
@@ -1,30 +1,30 @@
package jwc

import (
"crypto"
"crypto/aes"
"crypto/cipher"
"crypto/rsa"
"encoding/base64"
"encoding/json"
)

func newJWEA128GCM(protectedHeaders *JOSEHeaders, pubKey *rsa.PublicKey, plaintext []byte) (*JWE, error) {
func newJWEA128GCM(protectedHeaders *JOSEHeaders, pubKey crypto.PublicKey, plaintext []byte) (*JWE, error) {
cek, cipherCEK, cipherCEKB64, err := GenerateCEK(16, protectedHeaders.Algorithm, pubKey)
if err != nil {
return nil, err
}
return newGCM(cek, cipherCEK, cipherCEKB64, protectedHeaders, pubKey, plaintext)
}

func newJWEA256GCM(protectedHeaders *JOSEHeaders, pubKey *rsa.PublicKey, plaintext []byte) (*JWE, error) {
func newJWEA256GCM(protectedHeaders *JOSEHeaders, pubKey crypto.PublicKey, plaintext []byte) (*JWE, error) {
cek, cipherCEK, cipherCEKB64, err := GenerateCEK(32, protectedHeaders.Algorithm, pubKey)
if err != nil {
return nil, err
}
return newGCM(cek, cipherCEK, cipherCEKB64, protectedHeaders, pubKey, plaintext)
}

func newJWEA512GCM(protectedHeaders *JOSEHeaders, pubKey *rsa.PublicKey, plaintext []byte) (*JWE, error) {
func newJWEA512GCM(protectedHeaders *JOSEHeaders, pubKey crypto.PublicKey, plaintext []byte) (*JWE, error) {
cek, cipherCEK, cipherCEKB64, err := GenerateCEK(64, protectedHeaders.Algorithm, pubKey)
if err != nil {
return nil, err
Expand All @@ -37,7 +37,7 @@ func newGCM(
cipherCEK []byte,
cipherCEKB64 string,
protectedHeaders *JOSEHeaders,
pubKey *rsa.PublicKey,
pubKey crypto.PublicKey,
plaintext []byte,
) (*JWE, error) {
headersBytes, err := json.Marshal(protectedHeaders)
Expand Down
43 changes: 32 additions & 11 deletions jwe.factory.go
Expand Up @@ -2,15 +2,18 @@ package jwc

import (
"bytes"
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"encoding/base64"
"errors"
"io"
"strings"
)

// ParseCompactJWE -
func ParseCompactJWE(compact []byte, privKey *rsa.PrivateKey) (jwe *JWE, err error) {
func ParseCompactJWE(compact []byte) (jwe *JWE, err error) {
var (
jweFragments = strings.Split(string(compact), ".")
tagB64 string
Expand All @@ -33,7 +36,7 @@ func ParseCompactJWE(compact []byte, privKey *rsa.PrivateKey) (jwe *JWE, err err
}

// NewJWE -
func NewJWE(protectedHeaders *JOSEHeaders, pubKey *rsa.PublicKey, plaintext []byte) (*JWE, error) {
func NewJWE(protectedHeaders *JOSEHeaders, pubKey crypto.PublicKey, plaintext []byte) (*JWE, error) {
switch protectedHeaders.Encryption {
case A128CBCHS256:
return newJWEA128CBCHS256(protectedHeaders, pubKey, plaintext)
Expand All @@ -53,7 +56,7 @@ func NewJWE(protectedHeaders *JOSEHeaders, pubKey *rsa.PublicKey, plaintext []by
}

// GenerateCEK - generate plaintext encryption key
func GenerateCEK(byteLength int, alg Algorithm, pubKey *rsa.PublicKey) (cek []byte, cipherCEK []byte, cipherCEKB64 string, err error) {
func GenerateCEK(byteLength int, alg Algorithm, pubKey crypto.PublicKey) (cek []byte, cipherCEK []byte, cipherCEKB64 string, err error) {
cek = make([]byte, byteLength)
_, err = rand.Read(cek)
if err != nil {
Expand All @@ -62,10 +65,12 @@ func GenerateCEK(byteLength int, alg Algorithm, pubKey *rsa.PublicKey) (cek []by
rng := rand.Reader
switch alg {
case ROAEP:
cipherCEK, err = rsa.EncryptOAEP(sha256.New(), rng, pubKey, cek, nil)
pk := pubKey.(rsa.PublicKey)
cipherCEK, err = rsa.EncryptOAEP(sha256.New(), rng, &pk, cek, nil)
break
case RSA15:
cipherCEK, err = rsa.EncryptPKCS1v15(rng, pubKey, cek)
pk := pubKey.(rsa.PublicKey)
cipherCEK, err = rsa.EncryptPKCS1v15(rng, &pk, cek)
break
default:
return nil, nil, "", ErrUnsupportedAlgorithm
Expand All @@ -74,15 +79,14 @@ func GenerateCEK(byteLength int, alg Algorithm, pubKey *rsa.PublicKey) (cek []by
return cek, cipherCEK, cipherCEKB64, nil
}

// GenerateInitVector - generate initialisation vector
func GenerateInitVector(byteLength int) (iv []byte, ivB64 string, err error) {
iv = make([]byte, byteLength)
_, err = rand.Read(iv)
if err != nil {
// GenerateInitVector -
func GenerateInitVector(ivLen int) (iv []byte, ivB64 string, err error) {
iv = make([]byte, ivLen)
if _, err = io.ReadFull(rand.Reader, iv); err != nil {
return nil, "", err
}
ivB64 = base64.RawURLEncoding.EncodeToString(iv)
return iv, ivB64, nil
return iv, ivB64, err
}

// String2ASCII - ensure ASCII encoding
Expand All @@ -108,3 +112,20 @@ func Rune2ASCII(r rune) rune {
return r
}
}

// Pad -
func Pad(src []byte, blockSize int) []byte {
padding := blockSize - len(src)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(src, padtext...)
}

// Unpad -
func Unpad(src []byte) ([]byte, error) {
length := len(src)
unpadding := int(src[length-1])
if unpadding > length {
return nil, errors.New("unpad error. This could happen when incorrect encryption key is used")
}
return src[:(length - unpadding)], nil
}
15 changes: 9 additions & 6 deletions jwe.go
@@ -1,6 +1,7 @@
package jwc

import (
"crypto"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
Expand Down Expand Up @@ -65,7 +66,7 @@ func (jwe *JWE) Compact() []byte {
}

// Plaintext returns deciphered content
func (jwe *JWE) Plaintext(privKey *rsa.PrivateKey) (plaintext []byte, err error) {
func (jwe *JWE) Plaintext(privKey crypto.PrivateKey) (plaintext []byte, err error) {
headersBytes, err := base64.RawURLEncoding.DecodeString(jwe.ProtectedB64)
var headers JOSEHeaders
err = json.Unmarshal(headersBytes, &headers)
Expand All @@ -88,10 +89,11 @@ func (jwe *JWE) Plaintext(privKey *rsa.PrivateKey) (plaintext []byte, err error)
if err != nil {
return nil, err
}
plaintext = ciphertext
switch headers.Encryption {
case A128CBCHS256, A192CBCHS384, A256CBCHS512:
mode := cipher.NewCBCDecrypter(block, iv)
mode.CryptBlocks(plaintext, ciphertext[aes.BlockSize:])
mode.CryptBlocks(plaintext, ciphertext)
case A128GCM, A256GCM, A512GCM:
mode, err := cipher.NewGCM(block)
if err != nil {
Expand All @@ -108,20 +110,21 @@ func (jwe *JWE) Plaintext(privKey *rsa.PrivateKey) (plaintext []byte, err error)
default:
return nil, ErrUnsupportedEncryption
}
return plaintext, nil
plaintext, err = Unpad(plaintext)
return plaintext, err
}

func decipherCEK(alg Algorithm, cipherCEKB64 string, privKey *rsa.PrivateKey) (cek []byte, err error) {
func decipherCEK(alg Algorithm, cipherCEKB64 string, privKey crypto.PrivateKey) (cek []byte, err error) {
cipherCEK, err := base64.RawURLEncoding.DecodeString(cipherCEKB64)
if err != nil {
return nil, err
}
rng := rand.Reader
switch alg {
case RSA15:
return rsa.DecryptPKCS1v15(rng, privKey, cipherCEK)
return rsa.DecryptPKCS1v15(rng, privKey.(*rsa.PrivateKey), cipherCEK)
case ROAEP:
return rsa.DecryptOAEP(sha256.New(), rng, privKey, cipherCEK, nil)
return rsa.DecryptOAEP(sha256.New(), rng, privKey.(*rsa.PrivateKey), cipherCEK, nil)
default:
return nil, ErrUnsupportedAlgorithm
}
Expand Down

0 comments on commit 9c76051

Please sign in to comment.