Skip to content

Commit

Permalink
Add bitLength and byteLength types for bytes/bits length conversions
Browse files Browse the repository at this point in the history
  • Loading branch information
oleiade committed Apr 24, 2023
1 parent be1e251 commit b96901b
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 29 deletions.
22 changes: 11 additions & 11 deletions webcrypto/aes.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ type AESKeyGenParams struct {
Algorithm

// The length, in bits, of the key.
Length int64 `json:"length"`
Length bitLength `json:"length"`
}

// newAESKeyGenParams creates a new AESKeyGenParams object, from the
Expand All @@ -41,7 +41,7 @@ func newAESKeyGenParams(rt *goja.Runtime, normalized Algorithm, params goja.Valu

return &AESKeyGenParams{
Algorithm: normalized,
Length: algorithmLength,
Length: bitLength(algorithmLength),
}, nil
}

Expand Down Expand Up @@ -75,7 +75,7 @@ func (akgp *AESKeyGenParams) GenerateKey(
return nil, NewError(OperationError, "invalid key length")
}

randomKey := make([]byte, akgp.Length/8)
randomKey := make([]byte, akgp.Length.asByteLength())
if _, err := rand.Read(randomKey); err != nil {
// 4.
return nil, NewError(OperationError, "could not generate random key")
Expand All @@ -86,7 +86,7 @@ func (akgp *AESKeyGenParams) GenerateKey(
key.Type = SecretCryptoKeyType
key.Algorithm = AESKeyAlgorithm{
Algorithm: akgp.Algorithm,
Length: akgp.Length,
Length: int64(akgp.Length),
}

// 10.
Expand Down Expand Up @@ -190,7 +190,7 @@ func (aip *AESImportParams) ImportKey(
key := &CryptoKey{
Algorithm: AESKeyAlgorithm{
Algorithm: aip.Algorithm,
Length: int64(len(keyData) * 8),
Length: int64(byteLength(len(keyData)).asBitLength()),
},
Type: SecretCryptoKeyType,
handle: keyData,
Expand Down Expand Up @@ -443,7 +443,7 @@ type AESGCMParams struct {
// in some applications: Appendix C of the specification provides additional guidance here.
//
// tagLength is optional and defaults to 128 if it is not specified.
TagLength int `json:"tagLength"`
TagLength bitLength `json:"tagLength"`
}

// Encrypt encrypts the given plaintext using the AES-GCM algorithm, and returns the ciphertext.
Expand Down Expand Up @@ -477,7 +477,7 @@ func (agp *AESGCMParams) Encrypt(plaintext []byte, key CryptoKey) ([]byte, error
}

// 4.
var tagLength int
var tagLength bitLength
if agp.TagLength == 0 {
tagLength = 128
} else {
Expand All @@ -503,7 +503,7 @@ func (agp *AESGCMParams) Encrypt(plaintext []byte, key CryptoKey) ([]byte, error
return nil, NewError(OperationError, "could not create cipher")
}

gcm, err := cipher.NewGCMWithTagSize(block, tagLength/8)
gcm, err := cipher.NewGCMWithTagSize(block, int(tagLength.asByteLength()))
if err != nil {
return nil, NewError(ImplementationError, "could not create cipher")
}
Expand All @@ -526,7 +526,7 @@ func (agp *AESGCMParams) Encrypt(plaintext []byte, key CryptoKey) ([]byte, error
// [specification]: https://www.w3.org/TR/WebCryptoAPI/#aes-gcm
func (agp *AESGCMParams) Decrypt(ciphertext []byte, key CryptoKey) ([]byte, error) {
// 1.
var tagLength int
var tagLength bitLength
if agp.TagLength == 0 {
tagLength = 128
} else {
Expand All @@ -544,7 +544,7 @@ func (agp *AESGCMParams) Decrypt(ciphertext []byte, key CryptoKey) ([]byte, erro
// 2.
// Note that we multiply the length of the ciphertext by 8, in order
// to get the length in bits.
if len(ciphertext)*8 < tagLength {
if byteLength(len(ciphertext)).asBitLength() < tagLength {
return nil, NewError(OperationError, "ciphertext is too short")
}

Expand All @@ -571,7 +571,7 @@ func (agp *AESGCMParams) Decrypt(ciphertext []byte, key CryptoKey) ([]byte, erro
return nil, NewError(OperationError, "could not create AES cipher")
}

gcm, err := cipher.NewGCMWithTagSize(block, tagLength/8)
gcm, err := cipher.NewGCMWithTagSize(block, int(tagLength.asByteLength()))
if err != nil {
return nil, NewError(OperationError, "could not create GCM cipher")
}
Expand Down
31 changes: 13 additions & 18 deletions webcrypto/hmac.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,28 +98,31 @@ func (hkgp *HMACKeyGenParams) GenerateKey(
// part of the normalized algorithm, and as accessing the runtime from the
// callback below could lead to a race condition.
if !hkgp.Length.Valid {
var length bitLength
switch hkgp.Hash.Name {
case SHA1:
hkgp.Length = null.IntFrom(sha1.BlockSize * 8)
length = byteLength(sha1.BlockSize).asBitLength()
case SHA256:
hkgp.Length = null.IntFrom(sha256.BlockSize * 8)
length = byteLength(sha256.BlockSize).asBitLength()
case SHA384:
hkgp.Length = null.IntFrom(sha512.BlockSize * 8)
length = byteLength(sha512.BlockSize).asBitLength()
case SHA512:
hkgp.Length = null.IntFrom(sha512.BlockSize * 8)
length = byteLength(sha512.BlockSize).asBitLength()
default:
// This case should never happen, as the normalization algorithm
// should have thrown an error if the hash algorithm is invalid.
return nil, NewError(ImplementationError, "invalid hash algorithm: "+hkgp.Hash.Name)
}

hkgp.Length = null.IntFrom(int64(length))
}

if hkgp.Length.Int64 == 0 {
return nil, NewError(OperationError, "algorithm's length cannot be 0")
}

// 3.
randomKey := make([]byte, hkgp.Length.Int64/8)
randomKey := make([]byte, bitLength(hkgp.Length.Int64).asByteLength())
if _, err := rand.Read(randomKey); err != nil {
// 4.
return nil, NewError(OperationError, "failed to generate random key; reason: "+err.Error())
Expand Down Expand Up @@ -285,28 +288,20 @@ func (hip *HMACImportParams) ImportKey(
}

// 5. 6.
length := int64(len(keyData) * 8)
length := byteLength(len(keyData)).asBitLength()
if length == 0 {
return nil, NewError(DataError, "key length cannot be 0")
}

// 7.
if hip.Length.Valid {
if hip.Length.Int64 > length {
return nil, NewError(DataError, "key length cannot be greater than the length of the imported data")
}

if hip.Length.Int64 < length {
return nil, NewError(DataError, "key length cannot be less than the length of the imported data")
}

length = hip.Length.Int64
if hip.Length.Valid && hip.Length.Int64 != int64(length) {
return nil, NewError(DataError, "key length cannot be different from the length of the imported data")
}

// 8.
key := CryptoKey{
Type: SecretCryptoKeyType,
handle: keyData[:length/8],
handle: keyData[:length.asByteLength()],
}

// 9.
Expand All @@ -316,7 +311,7 @@ func (hip *HMACImportParams) ImportKey(
algorithm.Name = HMAC

// 11.
algorithm.Length = length
algorithm.Length = int64(length)

// 12.
algorithm.Hash = hash
Expand Down
16 changes: 16 additions & 0 deletions webcrypto/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,22 @@ import (
"github.com/dop251/goja"
)

// bitLength is a type alias for the length of a bits collection.
type bitLength int

// asByteLength returns the length of the bits collection in bytes.
func (b bitLength) asByteLength() byteLength {
return byteLength(b) / 8
}

// byteLength is a type alias for the length of a byte slice.
type byteLength int

// asBitLength returns the length of the byte slice in bits.
func (b byteLength) asBitLength() bitLength {
return bitLength(b) * 8
}

// ToBytes tries to return a byte slice from compatible types.
func ToBytes(data interface{}) ([]byte, error) {
switch dt := data.(type) {
Expand Down

0 comments on commit b96901b

Please sign in to comment.