Skip to content

Commit bd6ad79

Browse files
authored
Merge pull request #1100 from herwinw/openssl_kdf_scrypt
Add specs for OpenSSL::KDF.scrypt
2 parents fb68990 + a569f4b commit bd6ad79

File tree

1 file changed

+207
-0
lines changed

1 file changed

+207
-0
lines changed

library/openssl/kdf/scrypt_spec.rb

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
require_relative '../../../spec_helper'
2+
require 'openssl'
3+
4+
describe "OpenSSL::KDF.scrypt" do
5+
before :each do
6+
@defaults = {
7+
salt: "\x00".b * 16,
8+
N: 2**14,
9+
r: 8,
10+
p: 1,
11+
length: 32
12+
}
13+
end
14+
15+
it "creates the same value with the same input" do
16+
key = OpenSSL::KDF.scrypt("secret", **@defaults)
17+
key.should == "h\xB2k\xDF]\xDA\xE1.-(\xCF\xAC\x91D\x8F\xC2a\x9C\x9D\x17}\xF2\x84T\xD4)\xC2>\xFE\x93\xE3\xF4".b
18+
end
19+
20+
it "supports nullbytes embedded into the password" do
21+
key = OpenSSL::KDF.scrypt("sec\x00ret".b, **@defaults)
22+
key.should == "\xF9\xA4\xA0\xF1p\xF4\xF0\xCAT\xB4v\xEB\r7\x88N\xF7\x15]Ns\xFCwt4a\xC9\xC6\xA7\x13\x81&".b
23+
end
24+
25+
it "coerces the password into a String using #to_str" do
26+
pass = mock("pass")
27+
pass.should_receive(:to_str).and_return("secret")
28+
key = OpenSSL::KDF.scrypt(pass, **@defaults)
29+
key.should == "h\xB2k\xDF]\xDA\xE1.-(\xCF\xAC\x91D\x8F\xC2a\x9C\x9D\x17}\xF2\x84T\xD4)\xC2>\xFE\x93\xE3\xF4".b
30+
end
31+
32+
it "coerces the salt into a String using #to_str" do
33+
salt = mock("salt")
34+
salt.should_receive(:to_str).and_return("\x00".b * 16)
35+
key = OpenSSL::KDF.scrypt("secret", **@defaults, salt: salt)
36+
key.should == "h\xB2k\xDF]\xDA\xE1.-(\xCF\xAC\x91D\x8F\xC2a\x9C\x9D\x17}\xF2\x84T\xD4)\xC2>\xFE\x93\xE3\xF4".b
37+
end
38+
39+
it "coerces the N into an Integer using #to_int" do
40+
n = mock("N")
41+
n.should_receive(:to_int).and_return(2**14)
42+
key = OpenSSL::KDF.scrypt("secret", **@defaults, N: n)
43+
key.should == "h\xB2k\xDF]\xDA\xE1.-(\xCF\xAC\x91D\x8F\xC2a\x9C\x9D\x17}\xF2\x84T\xD4)\xC2>\xFE\x93\xE3\xF4".b
44+
end
45+
46+
it "coerces the r into an Integer using #to_int" do
47+
r = mock("r")
48+
r.should_receive(:to_int).and_return(8)
49+
key = OpenSSL::KDF.scrypt("secret", **@defaults, r: r)
50+
key.should == "h\xB2k\xDF]\xDA\xE1.-(\xCF\xAC\x91D\x8F\xC2a\x9C\x9D\x17}\xF2\x84T\xD4)\xC2>\xFE\x93\xE3\xF4".b
51+
end
52+
53+
it "coerces the p into an Integer using #to_int" do
54+
p = mock("p")
55+
p.should_receive(:to_int).and_return(1)
56+
key = OpenSSL::KDF.scrypt("secret", **@defaults, p: p)
57+
key.should == "h\xB2k\xDF]\xDA\xE1.-(\xCF\xAC\x91D\x8F\xC2a\x9C\x9D\x17}\xF2\x84T\xD4)\xC2>\xFE\x93\xE3\xF4".b
58+
end
59+
60+
it "coerces the length into an Integer using #to_int" do
61+
length = mock("length")
62+
length.should_receive(:to_int).and_return(32)
63+
key = OpenSSL::KDF.scrypt("secret", **@defaults, length: length)
64+
key.should == "h\xB2k\xDF]\xDA\xE1.-(\xCF\xAC\x91D\x8F\xC2a\x9C\x9D\x17}\xF2\x84T\xD4)\xC2>\xFE\x93\xE3\xF4".b
65+
end
66+
67+
it "accepts an empty password" do
68+
key = OpenSSL::KDF.scrypt("", **@defaults)
69+
key.should == "\xAA\xFC\xF5^E\x94v\xFFk\xE6\xF0vR\xE7\x13\xA7\xF5\x15'\x9A\xE4C\x9Dn\x18F_E\xD2\v\e\xB3".b
70+
end
71+
72+
it "accepts an empty salt" do
73+
key = OpenSSL::KDF.scrypt("secret", **@defaults, salt: "")
74+
key.should == "\x96\xACDl\xCB3/aN\xB0F\x8A#\xD7\x92\xD2O\x1E\v\xBB\xCE\xC0\xAA\xB9\x0F]\xB09\xEA8\xDD\e".b
75+
end
76+
77+
it "accepts a zero length" do
78+
key = OpenSSL::KDF.scrypt("secret", **@defaults, length: 0)
79+
key.should.empty?
80+
end
81+
82+
it "accepts an arbitrary length" do
83+
key = OpenSSL::KDF.scrypt("secret", **@defaults, length: 19)
84+
key.should == "h\xB2k\xDF]\xDA\xE1.-(\xCF\xAC\x91D\x8F\xC2a\x9C\x9D".b
85+
end
86+
87+
it "raises a TypeError when password is not a String and does not respond to #to_str" do
88+
-> {
89+
OpenSSL::KDF.scrypt(Object.new, **@defaults)
90+
}.should raise_error(TypeError, "no implicit conversion of Object into String")
91+
end
92+
93+
it "raises a TypeError when salt is not a String and does not respond to #to_str" do
94+
-> {
95+
OpenSSL::KDF.scrypt("secret", **@defaults, salt: Object.new)
96+
}.should raise_error(TypeError, "no implicit conversion of Object into String")
97+
end
98+
99+
it "raises a TypeError when N is not an Integer and does not respond to #to_int" do
100+
-> {
101+
OpenSSL::KDF.scrypt("secret", **@defaults, N: Object.new)
102+
}.should raise_error(TypeError, "no implicit conversion of Object into Integer")
103+
end
104+
105+
it "raises a TypeError when r is not an Integer and does not respond to #to_int" do
106+
-> {
107+
OpenSSL::KDF.scrypt("secret", **@defaults, r: Object.new)
108+
}.should raise_error(TypeError, "no implicit conversion of Object into Integer")
109+
end
110+
111+
it "raises a TypeError when p is not an Integer and does not respond to #to_int" do
112+
-> {
113+
OpenSSL::KDF.scrypt("secret", **@defaults, p: Object.new)
114+
}.should raise_error(TypeError, "no implicit conversion of Object into Integer")
115+
end
116+
117+
it "raises a TypeError when length is not an Integer and does not respond to #to_int" do
118+
-> {
119+
OpenSSL::KDF.scrypt("secret", **@defaults, length: Object.new)
120+
}.should raise_error(TypeError, "no implicit conversion of Object into Integer")
121+
end
122+
123+
it "treats salt as a required keyword" do
124+
-> {
125+
OpenSSL::KDF.scrypt("secret", **@defaults.except(:salt))
126+
}.should raise_error(ArgumentError, 'missing keyword: :salt')
127+
end
128+
129+
it "treats N as a required keyword" do
130+
-> {
131+
OpenSSL::KDF.scrypt("secret", **@defaults.except(:N))
132+
}.should raise_error(ArgumentError, 'missing keyword: :N')
133+
end
134+
135+
it "treats r as a required keyword" do
136+
-> {
137+
OpenSSL::KDF.scrypt("secret", **@defaults.except(:r))
138+
}.should raise_error(ArgumentError, 'missing keyword: :r')
139+
end
140+
141+
it "treats p as a required keyword" do
142+
-> {
143+
OpenSSL::KDF.scrypt("secret", **@defaults.except(:p))
144+
}.should raise_error(ArgumentError, 'missing keyword: :p')
145+
end
146+
147+
it "treats length as a required keyword" do
148+
-> {
149+
OpenSSL::KDF.scrypt("secret", **@defaults.except(:length))
150+
}.should raise_error(ArgumentError, 'missing keyword: :length')
151+
end
152+
153+
it "treats all keywords as required" do
154+
-> {
155+
OpenSSL::KDF.scrypt("secret")
156+
}.should raise_error(ArgumentError, 'missing keywords: :salt, :N, :r, :p, :length')
157+
end
158+
159+
it "requires N to be a power of 2" do
160+
-> {
161+
OpenSSL::KDF.scrypt("secret", **@defaults, N: 2**14 - 1)
162+
}.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
163+
end
164+
165+
it "requires N to be at least 2" do
166+
key = OpenSSL::KDF.scrypt("secret", **@defaults, N: 2)
167+
key.should == "\x06A$a\xA9!\xBE\x01\x85\xA7\x18\xBCEa\x82\xC5\xFEl\x93\xAB\xBD\xF7\x8B\x84\v\xFC\eN\xEBQ\xE6\xD2".b
168+
169+
-> {
170+
OpenSSL::KDF.scrypt("secret", **@defaults, N: 1)
171+
}.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
172+
173+
-> {
174+
OpenSSL::KDF.scrypt("secret", **@defaults, N: 0)
175+
}.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
176+
177+
-> {
178+
OpenSSL::KDF.scrypt("secret", **@defaults, N: -1)
179+
}.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
180+
end
181+
182+
it "requires r to be positive" do
183+
-> {
184+
OpenSSL::KDF.scrypt("secret", **@defaults, r: 0)
185+
}.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
186+
187+
-> {
188+
OpenSSL::KDF.scrypt("secret", **@defaults, r: -1)
189+
}.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
190+
end
191+
192+
it "requires p to be positive" do
193+
-> {
194+
OpenSSL::KDF.scrypt("secret", **@defaults, p: 0)
195+
}.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
196+
197+
-> {
198+
OpenSSL::KDF.scrypt("secret", **@defaults, p: -1)
199+
}.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
200+
end
201+
202+
it "requires length to be not negative" do
203+
-> {
204+
OpenSSL::KDF.scrypt("secret", **@defaults, length: -1)
205+
}.should raise_error(ArgumentError, "negative string size (or size too big)")
206+
end
207+
end

0 commit comments

Comments
 (0)