Module: Armor
- Defined in:
- lib/armor.rb
Constant Summary collapse
- Digest =
RUBY_VERSION >= "2.1.0" ? OpenSSL::Digest : OpenSSL::Digest::Digest
Class Method Summary collapse
-
.compare(a, b) ⇒ Object
Time-attack safe comparison operator.
-
.concatenate(digest, password, salt, iterations, i) ⇒ Object
The function F is the xor (^) of c iterations of chained PRFs.
-
.digest(password, salt) ⇒ Object
Syntactic sugar for the underlying mathematical definition of PBKDF2.
-
.hex(str) ⇒ Object
Binary to hex convenience method.
-
.pbkdf2(digest, password, salt, c, dk_len) ⇒ Object
The PBKDF2 key derivation function has five input parameters:.
- .randomize(digest, password, seed) ⇒ Object
- .xor(a, b) ⇒ Object
Class Method Details
.compare(a, b) ⇒ Object
Time-attack safe comparison operator.
100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/armor.rb', line 100 def self.compare(a, b) return false unless a.length == b.length cmp = b.bytes.to_a result = 0 a.bytes.each_with_index do |char, index| result |= char ^ cmp[index] end return result == 0 end |
.concatenate(digest, password, salt, iterations, i) ⇒ Object
The function F is the xor (^) of c iterations of chained PRFs. The first iteration of PRF uses Password as the PRF key and Salt concatenated to i encoded as a big-endian 32-bit integer.
Note that i is a 1-based index. Subsequent iterations of PRF use Password as the PRF key and the output of the previous PRF computation as the salt:
Definition:
F(Password, Salt, Iterations, i) = U1 ^ U2 ^ ... ^ Uc
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/armor.rb', line 77 def self.concatenate(digest, password, salt, iterations, i) # U1 -> password, salt and 1 encoded as big-endian 32-bit integer. u = randomize(digest, password, salt + [i].pack("N")) ret = u # U2 through Uc: 2.upto(iterations) do # calculate Un u = randomize(digest, password, u) # xor it with the previous results ret = xor(ret, u) end ret end |
.digest(password, salt) ⇒ Object
Syntactic sugar for the underlying mathematical definition of PBKDF2.
This function does not allow passing in of a dkLen (in other words does not allow truncation of the final derived key).
Returns: Binary representation of the derived key (DK).
The default value for iter is set to 5000, and it can be configured via ‘ENV`.
The default value for hash is “sha512”, and it can also be configured via ‘ENV`.
18 19 20 21 22 23 24 25 26 |
# File 'lib/armor.rb', line 18 def self.digest(password, salt) iter = ENV["ARMOR_ITER"] || 5000 hash = ENV["ARMOR_HASH"] || "sha512" digest = Digest.new(hash) length = digest.digest_length hex(pbkdf2(digest, password, salt, Integer(iter), length)) end |
.hex(str) ⇒ Object
Binary to hex convenience method.
33 34 35 |
# File 'lib/armor.rb', line 33 def self.hex(str) str.unpack("H*").first end |
.pbkdf2(digest, password, salt, c, dk_len) ⇒ Object
The PBKDF2 key derivation function has five input parameters:
DK = PBKDF2(PRF, Password, Salt, c, dkLen)
where:
-
PRF is a pseudorandom function of two parameters
-
Password is the master password from which a derived key is generated
-
Salt is a cryptographic salt
-
c is the number of iterations desired
-
dkLen is the desired length of the derived key
DK is the generated derived key.
51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/armor.rb', line 51 def self.pbkdf2(digest, password, salt, c, dk_len) blocks_needed = (dk_len.to_f / digest.size).ceil result = "" # main block-calculating loop: 1.upto(blocks_needed) do |n| result << concatenate(digest, password, salt, c, n) end # truncate to desired length: result.slice(0, dk_len) end |
.randomize(digest, password, seed) ⇒ Object
28 29 30 |
# File 'lib/armor.rb', line 28 def self.randomize(digest, password, seed) OpenSSL::HMAC.digest(digest, password, seed) end |
.xor(a, b) ⇒ Object
113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/armor.rb', line 113 def self.xor(a, b) result = "".encode("ASCII-8BIT") b_bytes = b.bytes.to_a a.bytes.each_with_index do |c, i| result << (c ^ b_bytes[i]) end result end |