sjcl 0.0.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: []