Class: Zwiebel::Utilities

Inherits:
Object
  • Object
show all
Defined in:
lib/zwiebel/utilities.rb

Constant Summary collapse

SALT_LENGTH =
16
MAC_LENGTH =
32
S_KEY_LENGTH =
32
S_IV_LENGTH =
16

Class Method Summary collapse

Class Method Details

.current_time_periodObject



25
26
27
28
29
30
# File 'lib/zwiebel/utilities.rb', line 25

def self.current_time_period
  # tor rend-spec-v3
  # 2.2.1 [TIME-PERIODS]
  current_time = Time.now.utc.to_i
  (current_time / 60 - 1440) / 1440
end

.decrypt_layer(encrypted_data:, constant:, revision_counter:, subcredential:, blinded_key:) ⇒ Object



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/zwiebel/utilities.rb', line 32

def self.decrypt_layer(encrypted_data:, constant:, revision_counter:, subcredential:, blinded_key:)
  cleaned_data = encrypted_data.gsub("-----BEGIN MESSAGE-----\n", "").gsub("\n-----END MESSAGE-----", "")
  encrypted = Base64.decode64(cleaned_data)

  if encrypted.length < SALT_LENGTH + MAC_LENGTH
    raise ContentLengthError, "encrypted data should be at least #{SALT_LENGTH + MAC_LENGTH} bytes"
  end

  salt = encrypted.byteslice(0, SALT_LENGTH)
  ciphertext = encrypted.byteslice(SALT_LENGTH..-(MAC_LENGTH + 1))
  expected_mac = encrypted.byteslice(-MAC_LENGTH..-1)

  key_digest = blinded_key + subcredential + [revision_counter].pack("Q>") + salt + constant
  bit_length = (S_KEY_LENGTH + S_IV_LENGTH + MAC_LENGTH) * 8

  keys = Shake256.new(bit_length: bit_length, message_type: "hex").hexdigest(key_digest.unpack1("H*"))
  keys = [keys].pack("H*")

  secret_key = keys.byteslice(0, S_KEY_LENGTH)
  secret_iv = keys.byteslice(S_KEY_LENGTH, S_IV_LENGTH)
  mac_key = keys.byteslice(S_KEY_LENGTH + S_IV_LENGTH, MAC_LENGTH)

  mac_prefix = [mac_key.length].pack("Q>") + mac_key + [salt.length].pack("Q>") + salt
  mac_for = OpenSSL::Digest.digest("SHA3-256", mac_prefix + ciphertext)

  if expected_mac != mac_for
    raise DataError, "incorrect message authentication code"
  end

  decipher = OpenSSL::Cipher.new("aes-256-ctr")
  decipher.decrypt
  decipher.key = secret_key
  decipher.iv = secret_iv
  decipher.update(ciphertext) + decipher.final
end