sjcl 0.0.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 29f8b5de12d94ed4a88c0bc39573a2e6b0448231
4
- data.tar.gz: 3a042cd7897783efa68a1ed3c1303ac823f23218
3
+ metadata.gz: 9bc27222ca1e75a41a1db9f11f8cb007b6a79874
4
+ data.tar.gz: 999c3ec4e08aef5f06daa2d60f6756f93f94331a
5
5
  SHA512:
6
- metadata.gz: b45ef4f755370378ffdc7b84f80509032789a2c3efdd7a8e0fbbd25422c4d60d97ca89b1928c7420c9dcd388593b55b544cd260a897f5859ae9af32ee0c2739c
7
- data.tar.gz: c7dc290ae0bc477bdee3e62eece162f7671be51ab4908b7c35d926d431cd6a33efe41653aa17115f2bcca1890a8c58cfd0b62362e33ff15c1bfa8e515b61a44d
6
+ metadata.gz: 716feceacd1b35b785cb122cf53aeb2735292b9e0765da504779fa5ff49fd13c3b4411ad9bb8215d753fcb8b0f3ff5c44270d4510cdd7157c5e350304f097e53
7
+ data.tar.gz: 1c8821376b8969072246b53058dc163b5250de237ed80aca1954d33f88f8f332993f9c478439d4b774ce7ad5c6a597084c5d743328a2f88daea865518e2f17c0
data/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  A Ruby gem to interop with SJCL in AES-CCM mode.
5
5
 
6
- Defaults to 256 bit AES in CCM mode with 10_000 iteration PBKDF2
6
+ Defaults to 256 bit AES in CCM mode with 100_000 iterations PBKDF2
7
7
 
8
8
  ### Install
9
9
 
@@ -14,14 +14,24 @@ gem install sjcl
14
14
  enc = SJCL.encrypt('password', "Something to encrypt")
15
15
  dec = SJCL.decrypt('password', enc)
16
16
 
17
- ### Dev Notes
17
+ # Custom number of PBKDF2 iterations
18
+ enc = SJCL.encrypt('password', "Something to encrypt", {:iter => 10_000})
18
19
 
19
- This is a very naive implementation of SJCL's AES library in ruby.
20
- It's not been optimized for performance and instead tries to be a very
21
- close approximation of SJCL in terms of code and organization.
20
+ ### Usage
21
+
22
+ dec = SJCL.decrypt('password', enc)
23
+
24
+ ### Dev Goals
25
+
26
+ - Should be 100% compatible with SJCL Javascript library in AES-CCM mode
27
+ - Should not be dependent upon OpenSSL having been compiles with AES-CCM-256 support (May be slower)
22
28
 
23
29
  ### TODO
24
30
 
25
- - More modes
26
31
  - Test interop with node module directly
27
- - Test more scenarios
32
+
33
+ ### Changelog
34
+
35
+ - 1.0.0
36
+ - Update to use OpenSSL PBKDF2 function for increased speed
37
+ - Increase default iterations to 100,000
data/Rakefile CHANGED
@@ -4,7 +4,7 @@ require "rspec/core/rake_task"
4
4
 
5
5
  RSpec::Core::RakeTask.new(:rspec) do |spec|
6
6
  spec.pattern = 'spec/**/*_spec.rb'
7
- spec.rspec_opts = ['-cfs --backtrace']
7
+ spec.rspec_opts = ['--format documentation', '--backtrace']
8
8
  end
9
9
 
10
10
  task :default => :rspec
@@ -12,7 +12,7 @@ require 'base64'
12
12
  module SJCL
13
13
 
14
14
  DEFAULT = {
15
- v:1, iter:10000, ks:256, ts:64,
15
+ iter:100_000, ks:256, ts:64,
16
16
  mode:"ccm", adata:"", cipher:"aes"
17
17
  }
18
18
 
@@ -5,166 +5,10 @@ module SJCL
5
5
  module Misc
6
6
 
7
7
  def self.pbkdf2(password, salt, iter, length)
8
- salt = Base64.decode64(salt)
9
- key = SJCL::PBKDF2.new(:password=>password,
10
- :salt=>salt,
11
- :key_length => length/8,
12
- :iterations=>iter).hex_string
13
- SJCL::Codec::Hex.toBits(key)
8
+ key = OpenSSL::PKCS5.pbkdf2_hmac(password, Base64.decode64(salt), iter, length/8, 'SHA256')
9
+ SJCL::Codec::Hex.toBits(key.unpack('H*')[0])
14
10
  end
15
11
 
16
12
  end
17
13
  end
18
14
 
19
-
20
- # Pilfered from https://github.com/emerose and updated to Ruby >2.0
21
- class SJCL::PBKDF2
22
- def initialize(opts={})
23
- @hash_function = OpenSSL::Digest.new("sha256")
24
-
25
- # override with options
26
- opts.each_key do |k|
27
- if self.respond_to?("#{k}=")
28
- self.send("#{k}=", opts[k])
29
- else
30
- raise ArgumentError, "Argument '#{k}' is not allowed"
31
- end
32
- end
33
-
34
- yield self if block_given?
35
-
36
- # set this to the default if nothing was given
37
- @key_length ||= @hash_function.size
38
-
39
- # make sure the relevant things got set
40
- raise ArgumentError, "password not set" if @password.nil?
41
- raise ArgumentError, "salt not set" if @salt.nil?
42
- raise ArgumentError, "iterations not set" if @iterations.nil?
43
- end
44
- attr_reader :key_length, :hash_function, :iterations, :salt, :password
45
-
46
- def key_length=(l)
47
- raise ArgumentError, "key too short" if l < 1
48
- raise ArgumentError, "key too long" if l > ((2**32 - 1) * @hash_function.size)
49
- @value = nil
50
- @key_length = l
51
- end
52
-
53
- def hash_function=(h)
54
- @value = nil
55
- @hash_function = find_hash(h)
56
- end
57
-
58
- def iterations=(i)
59
- raise ArgumentError, "iterations can't be less than 1" if i < 1
60
- @value = nil
61
- @iterations = i
62
- end
63
-
64
- def salt=(s)
65
- @value = nil
66
- @salt = s
67
- end
68
-
69
- def password=(p)
70
- @value = nil
71
- @password = p
72
- end
73
-
74
- def value
75
- calculate! if @value.nil?
76
- @value
77
- end
78
-
79
- alias bin_string value
80
-
81
- def hex_string
82
- bin_string.unpack("H*").first
83
- end
84
-
85
- # return number of milliseconds it takes to complete one iteration
86
- def benchmark(iters = 400000)
87
- iter_orig = @iterations
88
- @iterations=iters
89
- start = Time.now
90
- calculate!
91
- time = Time.now - start
92
- @iterations = iter_orig
93
- return (time/iters)
94
- end
95
-
96
- protected
97
-
98
- # finds and instantiates, if necessary, a hash function
99
- def find_hash(hash)
100
- case hash
101
- when Class
102
- # allow people to pass in classes to be instantiated
103
- # (eg, pass in OpenSSL::Digest::SHA1)
104
- hash = find_hash(hash.new)
105
- when Symbol
106
- # convert symbols to strings and see if OpenSSL::Digest can make sense of
107
- hash = find_hash(hash.to_s)
108
- when String
109
- # if it's a string, first strip off any leading 'hmacWith' (which is implied)
110
- hash.gsub!(/^hmacWith/i,'')
111
- # see if the OpenSSL lib understands it
112
- hash = OpenSSL::Digest.new(hash)
113
- when OpenSSL::Digest
114
- when OpenSSL::Digest::Digest
115
- # ok
116
- else
117
- raise TypeError, "Unknown hash type: #{hash.class}"
118
- end
119
- hash
120
- end
121
-
122
- # the pseudo-random function defined in the spec
123
- def prf(data)
124
- OpenSSL::HMAC.digest(@hash_function, @password, data)
125
- end
126
-
127
- # this is a translation of the helper function "F" defined in the spec
128
- def calculate_block(block_num)
129
- # u_1:
130
- u = prf(salt+[block_num].pack("N"))
131
- ret = u
132
- # u_2 through u_c:
133
- 2.upto(@iterations) do
134
- # calculate u_n
135
- u = prf(u)
136
- # xor it with the previous results
137
- ret = str_xor(ret, u)
138
- end
139
- ret
140
- end
141
-
142
- # the bit that actually does the calculating
143
- def calculate!
144
- # how many blocks we'll need to calculate (the last may be truncated)
145
- blocks_needed = (@key_length.to_f / @hash_function.size).ceil
146
- # reset
147
- @value = ""
148
- # main block-calculating loop:
149
- 1.upto(blocks_needed) do |block_num|
150
- @value << calculate_block(block_num)
151
- end
152
- # truncate to desired length:
153
- @value = @value.slice(0,@key_length)
154
- @value
155
- end
156
-
157
- def str_xor(str1, str2)
158
- raise ArgumentError, "Can't bitwise-XOR a String with a non-String" \
159
- unless str1.kind_of? String
160
- raise ArgumentError, "Can't bitwise-XOR strings of different length" \
161
- unless str2.length == str1.length
162
- result = "".encode("ASCII-8BIT")
163
- o_bytes = str2.bytes.to_a
164
- str1.bytes.each_with_index do |c, i|
165
- result << (c ^ o_bytes[i])
166
- end
167
- result
168
- end
169
-
170
- end
@@ -1,3 +1,3 @@
1
1
  module SJCL
2
- VERSION = "0.0.1"
2
+ VERSION = "1.0.0"
3
3
  end
@@ -6,15 +6,15 @@ describe "the SJCL AES cipher" do
6
6
  expectedEnc = [-1029611070, -1587456955, 1398035525, 17593584058368, -473824721, 1118000746, 301400623, 1117979183, -340453629, -1458159255, -1193196730, -96321175, -1019810258, 1780526919, -759043071, 679718248, 665037594, 1300431965, -1623005092, -1212070604, 1338880947, 38713326, -1660133454, 718084742, -764414122, -803127112, 1294802698, 1742734732, 1929679827, -1557802133, -301413279, -1981232659, 1759102580, -872671969, 636803454, -1407446893, -283960603, 619646970, 18601604, -1391999465, 480766576, 944301450, 961753870, -1806371559]
7
7
  expectedDec = [480766576, -1806371559, 961753870, 944301450, -286319329, -615496010, 2062433761, -793409572, -2072105771, -1581352105, -1436829123, 1046125251, -1529599379, 199606634, -1811865346, -1171999210, -614676899, -1612389996, 774215400, 519085179, 1932300365, -1312721028, 819268243, -978560474, -1259908556, -2129363473, -176598859, -1233073557, 8079113, 1953312090, 1140431582, 40343647, -1507275254, 932493188, 1100874369, 35446614, 1689034073, 1980413189, 1132649943, -1540091556, -1029611070, 17593584058368, 1398035525, -1587456955]
8
8
  cipher = SJCL::Cipher::AES.new([-1029611070, -1587456955, 1398035525, 17593584058368])
9
- SJCL::BitArray.compare(cipher.key[0], expectedEnc).should be_true
10
- SJCL::BitArray.compare(cipher.key[1], expectedDec).should be_true
9
+ SJCL::BitArray.compare(cipher.key[0], expectedEnc).should be_truthy
10
+ SJCL::BitArray.compare(cipher.key[1], expectedDec).should be_truthy
11
11
  end
12
12
  it "should match at 256bits" do
13
13
  expectedEnc = [1181708080, 1181708080, 1181708080, 1181708080, 1181708080, 1181708080, 1181708080, 1181708080, -272143510, -1448606630, -272143510, -1448606630, -1783784050, -742198594, -1783784050, -742198594, -934361844, 1642512726, -1910396356, 663334502, 1493858749, -1966568701, 526718605, -861412301, -1876490681, -238958831, 2145414445, 1483326283, 871585550, -1187259379, -1503737216, 1794715315, 18246469, -254301100, -1892171399, -681704910, 1034625069, -2070873056, 583939744, 1211570195, -1950673385, 2070723139, -195331270, 587561224, 465606173, -1622119875, -1113695075, -173456242, 2023755761, 63747506, -141046136, -728582272, 1401896912, -857778707, 1900087664, -2065150466, -1555843922, -1601240804, 1461243796, -2088077292]
14
14
  expectedDec = [-1555843922, -2088077292, 1461243796, -1601240804, -349970150, 681329711, -584960127, 1016916195, 431432362, 457480884, -564876537, -1173387270, 1389592494, -172067922, -507584670, -675345927, 199160848, -988794445, 1683696893, -1548180144, 1369923852, 335588556, 906090139, -2056489385, 1985048176, -1588912818, -941389395, -1469689536, 507794320, 570522199, -1284661044, -724887717, -1929777810, 1722324195, 1871042797, -566804688, 1011165639, -1855137125, 1738979223, -896580405, -363759219, 153963534, -1313675299, 1389285982, -1389759652, -154505972, -1389759652, -154505972, -478399101, -1197495341, -478399101, -1197495341, 1541643856, 1541643856, 1541643856, 1541643856, 1181708080, 1181708080, 1181708080, 1181708080]
15
15
  cipher = SJCL::Cipher::AES.new(SJCL::Codec::UTF8String.toBits("Foo0Foo0Foo0Foo0Foo0Foo0Foo0Foo0"))
16
- SJCL::BitArray.compare(cipher.key[0], expectedEnc).should be_true
17
- SJCL::BitArray.compare(cipher.key[1], expectedDec).should be_true
16
+ SJCL::BitArray.compare(cipher.key[0], expectedEnc).should be_truthy
17
+ SJCL::BitArray.compare(cipher.key[1], expectedDec).should be_truthy
18
18
  end
19
19
  end
20
20
 
@@ -25,11 +25,11 @@ describe "the SJCL AES cipher" do
25
25
  it "should encrypt data" do
26
26
  expectedEnc = [1991380212, -38165922, 194830393, 500234942] # Taken from SJCL JS
27
27
  enc = cipher.encrypt(data)
28
- SJCL::BitArray.compare(enc, expectedEnc).should be_true
28
+ SJCL::BitArray.compare(enc, expectedEnc).should be_truthy
29
29
  end
30
30
  it "should decrypt data" do
31
31
  dec = cipher.decrypt(cipher.encrypt(data))
32
- SJCL::BitArray.compare(data, dec).should be_true
32
+ SJCL::BitArray.compare(data, dec).should be_truthy
33
33
  end
34
34
  end
35
35
  end
@@ -1,10 +1,14 @@
1
1
  require 'rubygems'
2
2
  require 'bundler/setup'
3
3
  require 'rspec'
4
- require 'rspec/autorun'
5
4
 
6
5
  require 'sjcl'
7
6
 
8
7
  RSpec.configure do |config|
9
- # some (optional) config here
8
+ config.mock_with :rspec do |c|
9
+ c.syntax = [:should, :expect]
10
+ end
11
+ config.expect_with :rspec do |c|
12
+ c.syntax = [:should, :expect]
13
+ end
10
14
  end
metadata CHANGED
@@ -1,41 +1,41 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sjcl
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mark Percival
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-03-17 00:00:00.000000000 Z
11
+ date: 2015-01-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - '>='
18
18
  - !ruby/object:Gem::Version
19
19
  version: '0'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ">="
24
+ - - '>='
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rspec
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ">="
31
+ - - '>='
32
32
  - !ruby/object:Gem::Version
33
33
  version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ">="
38
+ - - '>='
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  description:
@@ -45,8 +45,8 @@ executables: []
45
45
  extensions: []
46
46
  extra_rdoc_files: []
47
47
  files:
48
- - ".gitignore"
49
- - ".travis.yml"
48
+ - .gitignore
49
+ - .travis.yml
50
50
  - Gemfile
51
51
  - LICENSE
52
52
  - README.md
@@ -82,27 +82,18 @@ require_paths:
82
82
  - lib
83
83
  required_ruby_version: !ruby/object:Gem::Requirement
84
84
  requirements:
85
- - - ">="
85
+ - - '>='
86
86
  - !ruby/object:Gem::Version
87
87
  version: '0'
88
88
  required_rubygems_version: !ruby/object:Gem::Requirement
89
89
  requirements:
90
- - - ">="
90
+ - - '>='
91
91
  - !ruby/object:Gem::Version
92
92
  version: '0'
93
93
  requirements: []
94
94
  rubyforge_project: sjcl
95
- rubygems_version: 2.1.11
95
+ rubygems_version: 2.0.2
96
96
  signing_key:
97
97
  specification_version: 4
98
98
  summary: A Ruby library for interopping with SJCL's AES crypto
99
- test_files:
100
- - spec/aes_spec.rb
101
- - spec/bit_array_spec.rb
102
- - spec/ccm_spec.rb
103
- - spec/code_base64_spec.rb
104
- - spec/codec_string_spec.rb
105
- - spec/codex_hex_spec.rb
106
- - spec/integration_spec.rb
107
- - spec/pbkdf2_spec.rb
108
- - spec/spec_helper.rb
99
+ test_files: []