Class: Sandal::Enc::ACBC_HS

Inherits:
Object
  • Object
show all
Defined in:
lib/sandal/enc/acbc_hs.rb

Overview

Base implementation of the A*CBC-HS* family of encryption methods.

Direct Known Subclasses

A128CBC_HS256, A256CBC_HS512

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, aes_size, sha_size, alg) ⇒ ACBC_HS

Initialises a new instance; it’s probably easier to use one of the subclass constructors.

Parameters:

  • name (String)

    The JWA name of the encryption method.

  • aes_size (Integer)

    The size of the AES algorithm, in bits.

  • sha_size (Integer)

    The size of the SHA algorithm, in bits.

  • alg (#name, #encrypt_key, #decrypt_key)

    The algorithm to use to encrypt and/or decrypt the AES key.



22
23
24
25
26
27
28
29
# File 'lib/sandal/enc/acbc_hs.rb', line 22

def initialize(name, aes_size, sha_size, alg)
  @name = name
  @aes_size = aes_size
  @sha_size = sha_size
  @cipher_name = "aes-#{aes_size}-cbc"
  @alg = alg
  @digest = OpenSSL::Digest.new("sha#{@sha_size}")
end

Instance Attribute Details

#algObject (readonly)

The JWA algorithm used to encrypt the content master key.



14
15
16
# File 'lib/sandal/enc/acbc_hs.rb', line 14

def alg
  @alg
end

#nameObject (readonly)

The JWA name of the encryption method.



11
12
13
# File 'lib/sandal/enc/acbc_hs.rb', line 11

def name
  @name
end

Instance Method Details

#decrypt(token) ⇒ String

Decrypts an encrypted JSON Web Token.

Parameters:

  • token (String or Array)

    The token, or token parts, to decrypt.

Returns:

  • (String)

    The token payload.



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/sandal/enc/acbc_hs.rb', line 60

def decrypt(token)
  parts, decoded_parts = Sandal::Enc.token_parts(token)
  header, encrypted_key, iv, ciphertext, auth_tag = *decoded_parts

  key = @alg.decrypt_key(encrypted_key)
  mac_key, enc_key = derive_keys(key)

  auth_data = parts[0]
  auth_data_length = [auth_data.length * 8].pack("Q>")
  mac_input = [auth_data, iv, ciphertext, auth_data_length].join
  mac = OpenSSL::HMAC.digest(@digest, mac_key, mac_input)
  unless auth_tag == mac[0...(mac.length / 2)]
    raise Sandal::InvalidTokenError, "Invalid authentication tag."
  end

  cipher = OpenSSL::Cipher.new(@cipher_name).decrypt
  begin
    cipher.key = enc_key
    cipher.iv = decoded_parts[2]
    cipher.update(decoded_parts[3]) + cipher.final
  rescue OpenSSL::Cipher::CipherError => e
    raise Sandal::InvalidTokenError, "Cannot decrypt token: #{e.message}"
  end
end

#encrypt(header, payload) ⇒ String

Encrypts a token payload.

Parameters:

  • header (String)

    The header string.

  • payload (String)

    The payload.

Returns:

  • (String)

    An encrypted JSON Web Token.



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/sandal/enc/acbc_hs.rb', line 36

def encrypt(header, payload)
  key = get_encryption_key
  mac_key, enc_key = derive_keys(key)
  encrypted_key = @alg.encrypt_key(key)

  cipher = OpenSSL::Cipher.new(@cipher_name).encrypt
  cipher.key = enc_key
  cipher.iv = iv = SecureRandom.random_bytes(16)
  ciphertext = cipher.update(payload) + cipher.final

  auth_data = Sandal::Util.jwt_base64_encode(header)
  auth_data_length = [auth_data.length * 8].pack("Q>")
  mac_input = [auth_data, iv, ciphertext, auth_data_length].join
  mac = OpenSSL::HMAC.digest(@digest, mac_key, mac_input)
  auth_tag = mac[0...(mac.length / 2)]

  remainder = [encrypted_key, iv, ciphertext, auth_tag].map { |part| Sandal::Util.jwt_base64_encode(part) }
  [auth_data, *remainder].join(".")
end