Skip to content

Commit ed99f4f

Browse files
committed
Add additional tests, and minor meta updates
* Added some new tests * Updated default rake task to run both test and rubocop * Update SimpleCov to not test the coverage of the minitest suite itself
1 parent a931fbb commit ed99f4f

File tree

9 files changed

+170
-6
lines changed

9 files changed

+170
-6
lines changed

.github/workflows/ruby.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ jobs:
3333
- name: Test C library
3434
run: cd ext/argon2_wrap/ && make test && cd ../..
3535
- name: Run tests
36-
run: bundle exec rake
36+
run: bundle exec rake test
3737
- name: Coveralls Parallel
3838
uses: coverallsapp/github-action@master
3939
with:
@@ -54,7 +54,7 @@ jobs:
5454
- name: Install dependencies
5555
run: bundle install
5656
- name: Run rubocop
57-
run: bundle exec rubocop
57+
run: bundle exec rake rubocop
5858

5959
finish:
6060
runs-on: ubuntu-latest

Rakefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@ Rake::TestTask.new(:test) do |t|
1313
t.test_files = FileList['test/**/*_test.rb']
1414
end
1515

16-
task :default => :test
16+
task :default => %i[test rubocop]

test/api_test.rb

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,40 @@ def test_valid_hash
4141
secure_pass = Argon2::Password.create('A secret')
4242
assert Argon2::Password.valid_hash?(secure_pass)
4343
end
44+
45+
###############
46+
## New Tests ##
47+
###############
48+
ORIGINAL_PASSWORD = 'mypassword'
49+
PEPPER = 'A secret'
50+
51+
def test_create_password_without_parameters
52+
assert argon2 = Argon2::Password.create(ORIGINAL_PASSWORD)
53+
54+
assert argon2.is_a?(Argon2::Password)
55+
assert_equal argon2.m_cost, 16
56+
assert_equal argon2.t_cost, 2
57+
assert argon2.matches?(ORIGINAL_PASSWORD)
58+
assert Argon2::Password.verify_password(ORIGINAL_PASSWORD, argon2)
59+
end
60+
61+
def test_create_password_with_parameters
62+
assert argon2 = Argon2::Password.create(ORIGINAL_PASSWORD, t_cost: 4, m_cost: 12)
63+
64+
assert argon2.is_a?(Argon2::Password)
65+
assert_equal argon2.m_cost, 12
66+
assert_equal argon2.t_cost, 4
67+
assert argon2.matches?(ORIGINAL_PASSWORD)
68+
assert Argon2::Password.verify_password(ORIGINAL_PASSWORD, argon2)
69+
end
70+
71+
def test_create_password_with_secret
72+
assert argon2 = Argon2::Password.create(ORIGINAL_PASSWORD, secret: PEPPER)
73+
74+
assert argon2.is_a?(Argon2::Password)
75+
assert_equal argon2.m_cost, 16
76+
assert_equal argon2.t_cost, 2
77+
assert argon2.matches?(ORIGINAL_PASSWORD, PEPPER)
78+
assert Argon2::Password.verify_password(ORIGINAL_PASSWORD, argon2, PEPPER)
79+
end
4480
end

test/key_test.rb

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,73 @@ def test_key_hash
1010
assert basehash = Argon2::Password.create(PASS, t_cost: 2, m_cost: 16)
1111
# Keyed hash
1212
assert keyhash = Argon2::Password.create(PASS, t_cost: 2, m_cost: 16, secret: KEY)
13+
14+
# Isn't this test somewhat pointless? Each password will have a new salt,
15+
# so they can never match anyway.
1316
refute_equal basehash, keyhash
17+
18+
# Demonstrate problem:
19+
assert salthash = Argon2::Password.create(PASS, t_cost: 2, m_cost: 16)
20+
refute_equal basehash, salthash
21+
# Prove that it's not just the `==` being broken:
22+
assert_equal basehash, basehash
23+
assert_equal salthash, salthash
24+
assert_equal keyhash, keyhash
25+
1426
# The keyed hash - without the key
1527
refute Argon2::Password.verify_password(PASS, keyhash)
1628
# With key
1729
assert Argon2::Password.verify_password(PASS, keyhash, KEY)
1830
end
31+
32+
# So apparently the salt that's in the digest is actually different from the
33+
# salt used to generate the argon2 hash.
34+
#
35+
# To demonstrate:
36+
#
37+
# salt = Argon2::Engine.saltgen
38+
# argon2 = Argon2::Password.create('anysecret', salt_do_not_supply: salt)
39+
# salt == argon2.salt
40+
# => false
41+
# salt.length
42+
# => 16
43+
# argon2.salt.length
44+
# => 22
45+
# salt
46+
# => "\xCA\xFD\xED\x18\x10\xD1!R\xF2\xA9\f4\xD2\x966\x9D"
47+
# argon2.salt
48+
# => "yv3tGBDRIVLyqQw00pY2nQ"
49+
#
50+
# This combined with the fact that you're not supposed to supply the salt in
51+
# the first place, makes me wonder if we should just hard deprecate passing in
52+
# the salt at all. In its current state, it provides literally no value and
53+
# allows developers to shoot themselves in the foot.
54+
#
55+
# This test might be blown away soon anyway, temp disable abc cop.
56+
# rubocop:disable Metrics/AbcSize
57+
def test_key_hash_with_same_salts
58+
skip('The salt going in is not the same as the salt in the digest')
59+
assert basehash = Argon2::Password.create(PASS)
60+
assert salthash = Argon2::Password.create(PASS, salt_do_not_supply: basehash.salt)
61+
assert keyhash = Argon2::Password.create(PASS, salt_do_not_supply: basehash.salt, secret: KEY)
62+
63+
# Prove that you can create an identical copy
64+
assert_equal basehash, salthash
65+
# Prove that both hashes without peppers do not equal hash with pepper
66+
refute_equal basehash, keyhash
67+
refute_equal salthash, keyhash
68+
69+
# Test unkeyed hashes
70+
assert Argon2::Password.verify_password(PASS, basehash)
71+
assert Argon2::Password.verify_password(PASS, salthash)
72+
73+
refute Argon2::Password.verify_password(PASS, basehash, KEY)
74+
refute Argon2::Password.verify_password(PASS, salthash, KEY)
75+
76+
# Test keyed hash
77+
refute Argon2::Password.verify_password(PASS, keyhash)
78+
79+
assert Argon2::Password.verify_password(PASS, keyhash, KEY)
80+
end
81+
# rubocop:enable Metrics/AbcSize
1982
end

test/low_level_test.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
class LowLevelArgon2Test < Minitest::Test
88
def test_that_it_has_a_version_number
99
refute_nil ::Argon2::VERSION
10+
assert ::Argon2::VERSION.is_a?(String)
1011
end
1112

1213
def test_ffi_vector

test/test_helper.rb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@
1111
c.single_report_path = 'coverage/lcov.info'
1212
end
1313
SimpleCov.formatter = SimpleCov::Formatter::LcovFormatter
14-
SimpleCov.start
14+
SimpleCov.start do
15+
# Don't test the coverage of the test suite itself...
16+
add_filter '/test'
17+
end
1518

1619
require 'argon2'
1720

test/unicode_test.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,7 @@ def test_emoji
2424
hash = Argon2::Password.create(rawstr)
2525
assert Argon2::Password.verify_password(rawstr, hash)
2626
refute Argon2::Password.verify_password("", hash)
27+
# Also test if emoji are stripped but spaces remained.
28+
refute Argon2::Password.verify_password(" ", hash)
2729
end
2830
end

test/v3_tests/password_new_test.rb

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# frozen_string_literal: true
2+
3+
require 'test_helper'
4+
5+
class PasswordNewTest < Minitest::Test
6+
# TODO: Randomly generate a new password with Faker
7+
# SECRET = Faker::Internet.unique.password
8+
SECRET = 'mysecretpassword'
9+
PASS = Argon2::Password.create(SECRET)
10+
DIGEST = PASS.to_s
11+
# What would be appropriate bad digest(s) to test? Using a bcrypt hash for now
12+
BAD_DIGEST = '$2a$05$CCCCCCCCCCCCCCCCCCCCC.E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW'
13+
14+
def test_accepts_valid_string
15+
assert argon2 = Argon2::Password.new(DIGEST)
16+
assert argon2.is_a?(Argon2::Password)
17+
18+
assert_equal argon2, PASS
19+
assert_equal argon2.to_s, DIGEST
20+
21+
assert argon2.matches?(SECRET)
22+
assert Argon2::Password.verify_password(SECRET, argon2)
23+
assert Argon2::Password.verify_password(argon2, DIGEST)
24+
end
25+
26+
def test_rejects_invalid_string
27+
assert_raises Argon2::Errors::InvalidHash do
28+
Argon2::Password.new(BAD_DIGEST)
29+
end
30+
end
31+
32+
def test_accepts_argon2_password
33+
assert argon2 = Argon2::Password.new(PASS)
34+
assert argon2.is_a?(Argon2::Password)
35+
36+
assert_equal argon2, PASS
37+
assert_equal argon2.to_s, DIGEST
38+
39+
assert argon2.matches?(SECRET)
40+
assert Argon2::Password.verify_password(SECRET, argon2)
41+
assert Argon2::Password.verify_password(argon2, DIGEST)
42+
end
43+
end

test/v3_tests/verify_password_test.rb

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,35 @@ class VerifyPasswordTest < Minitest::Test
1313
OTHER_PASS = Argon2::Password.create(OTHER_SECRET)
1414
OTHER_DIGEST = OTHER_PASS.to_s
1515

16-
def test_accepts_string
16+
def test_accepts_string_as_secret
1717
assert Argon2::Password.verify_password(SECRET, DIGEST)
1818
assert Argon2::Password.verify_password(OTHER_SECRET, OTHER_DIGEST)
1919

2020
refute Argon2::Password.verify_password(SECRET, OTHER_DIGEST)
2121
refute Argon2::Password.verify_password(OTHER_SECRET, DIGEST)
2222
end
2323

24-
def test_accepts_argon2_password
24+
def test_accepts_argon2_password_as_secret
2525
assert Argon2::Password.verify_password(PASS, DIGEST)
2626
assert Argon2::Password.verify_password(OTHER_PASS, OTHER_DIGEST)
2727

2828
refute Argon2::Password.verify_password(PASS, OTHER_DIGEST)
2929
refute Argon2::Password.verify_password(OTHER_PASS, DIGEST)
3030
end
31+
32+
def test_accepts_argon2_password_as_digest
33+
assert Argon2::Password.verify_password(SECRET, PASS)
34+
assert Argon2::Password.verify_password(OTHER_SECRET, OTHER_PASS)
35+
36+
refute Argon2::Password.verify_password(SECRET, OTHER_PASS)
37+
refute Argon2::Password.verify_password(OTHER_SECRET, PASS)
38+
end
39+
40+
def test_accepts_tautology
41+
assert Argon2::Password.verify_password(PASS, PASS)
42+
assert Argon2::Password.verify_password(OTHER_PASS, OTHER_PASS)
43+
44+
refute Argon2::Password.verify_password(PASS, OTHER_PASS)
45+
refute Argon2::Password.verify_password(OTHER_PASS, PASS)
46+
end
3147
end

0 commit comments

Comments
 (0)