openssl-cmac 1.0.0 → 2.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 63fc4231601c14a5a8a6fc04bdcc4291b7be2cda
4
+ data.tar.gz: cbcabe5e112d41adf149d6eac700157569731636
5
+ SHA512:
6
+ metadata.gz: 3d1d6128a6a4c99b71461f7d14411502215e19aa33779f38d907203d62333052000cd3aed8c4f1a1d3706bf0f554ea7ce70a2b44173145683e345343d92486ca
7
+ data.tar.gz: a86fc591bd98f5505986c1807d61a32214a9892366553268e3e3791c90865a6c339520a0d8929de1322030a1eca837643018af5655800e03ac79c8599dbbd483
data/.rubocop.yml ADDED
@@ -0,0 +1,12 @@
1
+
2
+ ClassLength:
3
+ Max: 256
4
+
5
+ MethodLength:
6
+ Max: 32
7
+
8
+ CyclomaticComplexity:
9
+ Max: 8
10
+
11
+ Documentation:
12
+ Enabled: false
data/.yardopts ADDED
@@ -0,0 +1,4 @@
1
+ --no-private
2
+ --protected
3
+ lib/**/**/*.rb -
4
+ LICENSE
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'rake', '>=10.2.2'
4
+ gem 'rdoc', '>=4.1.1'
5
+ gem 'yard', '>=0.8.7.3'
6
+ gem 'rubocop', '>=0.18.1'
7
+ gem 'coveralls', '>=00.7.0'
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014, Maxim Chechel, Lars Schmertmann <SmallLars@t-online.de>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,43 @@
1
+ [![Gem Version](https://badge.fury.io/rb/openssl-cmac.png)](http://badge.fury.io/rb/openssl-cmac)
2
+ [![Dependency Status](https://gemnasium.com/SmallLars/openssl-cmac.png)](https://gemnasium.com/SmallLars/openssl-cmac)
3
+ [![Build Status](https://travis-ci.org/SmallLars/openssl-cmac.png?branch=master)](https://travis-ci.org/SmallLars/openssl-cmac)
4
+ [![Coverage Status](https://coveralls.io/repos/SmallLars/openssl-cmac/badge.png?branch=master)](https://coveralls.io/r/SmallLars/openssl-cmac)
5
+ [![Code Climate](https://codeclimate.com/github/SmallLars/openssl-cmac.png)](https://codeclimate.com/github/SmallLars/openssl-cmac)
6
+ [![Inline docs](http://inch-pages.github.io/github/smalllars/openssl-cmac.png)](http://inch-pages.github.io/github/smalllars/openssl-cmac)
7
+
8
+ # openssl-cmac
9
+
10
+ Ruby Gem for
11
+ * [RFC 4493 - The AES-CMAC Algorithm](http://tools.ietf.org/html/rfc4493)
12
+ * [RFC 4494 - The AES-CMAC-96 Algorithm and Its Use with IPsec](http://tools.ietf.org/html/rfc4494)
13
+ * [RFC 4615 - The Advanced Encryption Standard-Cipher-based Message Authentication Code-Pseudo-Random Function-128 (AES-CMAC-PRF-128) Algorithm for the Internet Key Exchange Protocol (IKE)](http://tools.ietf.org/html/rfc4615)
14
+
15
+ ## Installation
16
+
17
+ Add this line to your application's Gemfile:
18
+
19
+ gem 'openssl-cmac'
20
+
21
+ And then execute:
22
+
23
+ $ bundle
24
+
25
+ Or install it yourself as:
26
+
27
+ $ gem install openssl-cmac
28
+
29
+ ## Usage
30
+
31
+ Example 1:
32
+
33
+ require 'openssl/cmac'
34
+ mac = OpenSSL::CMAC.digest('AES', 'message', 'key')
35
+
36
+ Example 2:
37
+
38
+ require 'openssl/cmac'
39
+ cmac = OpenSSL::CMAC.new('AES', 'key')
40
+ cmac.update('message chunk 1')
41
+ ...
42
+ cmac.update('message chunk n')
43
+ mac = cmac.digest
data/Rakefile ADDED
@@ -0,0 +1,31 @@
1
+ require './lib/openssl/cmac/version'
2
+ require "bundler/gem_tasks"
3
+ require 'rake/testtask'
4
+
5
+ task :default => :build
6
+
7
+ desc "Run tests"
8
+ Rake::TestTask.new do |t|
9
+ t.libs << 'test'
10
+ end
11
+
12
+ desc "Create documentation"
13
+ task :doc do
14
+ sh "gem rdoc --rdoc openssl-cmac"
15
+ sh "yardoc"
16
+ end
17
+
18
+ desc "Uninstall and clean documentation"
19
+ task :clean do
20
+ sh "gem uninstall openssl-cmac"
21
+ begin; sh "rm -R ./coverage"; rescue; end
22
+ begin; sh "rm -R ./.yardoc"; rescue; end
23
+ begin; sh "rm -R ./doc"; rescue; end
24
+ end
25
+
26
+ desc "Development Dependencies"
27
+ task (:devinst) { sh "gem install --dev ./openssl-cmac-#{OpenSSL::CMAC::VERSION}.gem" }
28
+
29
+ desc "Bundle install"
30
+ task (:bundle) { sh "bundle install" }
31
+
@@ -0,0 +1,5 @@
1
+ module OpenSSL
2
+ class CMAC
3
+ VERSION = '2.0.0'
4
+ end
5
+ end
@@ -0,0 +1,168 @@
1
+ require 'openssl'
2
+
3
+ module OpenSSL
4
+ # CMACError used for wrong parameter resonse.
5
+ class CMACError < StandardError
6
+ end
7
+
8
+ # Abstract from http://tools.ietf.org/html/rfc4493:
9
+ #
10
+ # The National Institute of Standards and Technology (NIST) has
11
+ # recently specified the Cipher-based Message Authentication Code
12
+ # (CMAC), which is equivalent to the One-Key CBC MAC1 (OMAC1) submitted
13
+ # by Iwata and Kurosawa. This memo specifies an authentication
14
+ # algorithm based on CMAC with the 128-bit Advanced Encryption Standard
15
+ # (AES). This new authentication algorithm is named AES-CMAC. The
16
+ # purpose of this document is to make the AES-CMAC algorithm
17
+ # conveniently available to the Internet Community.
18
+ #
19
+ # http://tools.ietf.org/html/rfc4494
20
+ # reduces the length of the result from 16 to 12 Byte.
21
+ #
22
+ # http://tools.ietf.org/html/rfc4615
23
+ # allows to use variable key sizes.
24
+ class CMAC
25
+ # Searches for supported algorithms within OpenSSL
26
+ #
27
+ # @return [[String]] supported algorithms
28
+ def self.ciphers
29
+ l = OpenSSL::Cipher.ciphers.keep_if { |c| c.end_with?('-128-CBC') }
30
+ l.length.times { |i| l[i] = l[i][0..-9] }
31
+ l
32
+ end
33
+
34
+ # Returns the authentication code as a binary string. The cipher parameter
35
+ # must be an entry of OpenSSL::CMAC.ciphers.
36
+ #
37
+ # @param cipher [String] entry of OpenSSL::CMAC.ciphers
38
+ # @param key [String] binary key string
39
+ # @param data [String] binary data string
40
+ # @param length [Number] length of the authentication code
41
+ #
42
+ # @return [String] authentication code
43
+ def self.digest(cipher, key, data, length = 16)
44
+ CMAC.new(cipher, key).update(data).digest(length)
45
+ end
46
+
47
+ public
48
+
49
+ # Returns an instance of OpenSSL::CMAC set with the cipher algorithm and
50
+ # key to be used. The instance represents the initial state of the message
51
+ # authentication code before any data has been processed. To process data
52
+ # with it, use the instance method update with your data as an argument.
53
+ #
54
+ # @param cipher [String] entry of OpenSSL::CMAC.ciphers
55
+ # @param key [String] binary key string
56
+ #
57
+ # @return [Object] the new CMAC object
58
+ def initialize(cipher, key = '')
59
+ unless CMAC.ciphers.include?(cipher)
60
+ fail CMACError, "unsupported cipher algorithm (#{cipher})"
61
+ end
62
+
63
+ @keys = []
64
+ @buffer = ''.force_encoding('ASCII-8BIT')
65
+ @cipher = OpenSSL::Cipher.new("#{cipher}-128-CBC")
66
+
67
+ self.key = key unless key == ''
68
+ end
69
+
70
+ # Returns self as it was when it was first initialized with new key,
71
+ # with all processed data cleared from it.
72
+ #
73
+ # @param key [String] binary key string
74
+ #
75
+ # @return [Object] self with initial state and new key
76
+ def key=(key)
77
+ reset
78
+ key = CMAC.digest('AES', "\x00" * 16, key, 16) unless key.b.length == 16
79
+
80
+ @keys[0] = key.dup
81
+ @cipher.key = @keys[0]
82
+
83
+ cipher = OpenSSL::Cipher.new(@cipher.name)
84
+ cipher.encrypt
85
+ cipher.key = @keys[0]
86
+ k = cipher.update("\x00" * 16).bytes
87
+ 1.upto(2) do |i|
88
+ k = k.pack('C*').unpack('B*')[0]
89
+ msb = k.slice!(0)
90
+ k = [k, '0'].pack('B*').bytes
91
+ k[15] ^= 0x87 if msb == '1'
92
+ @keys[i] = k.dup
93
+ end
94
+ self
95
+ end
96
+
97
+ # Alias for: update
98
+ def <<(data)
99
+ update(data)
100
+ end
101
+
102
+ # Returns the block length of the used cipher algorithm.
103
+ #
104
+ # @return [Number] length of the used cipher algorithm
105
+ def block_length
106
+ 16
107
+ end
108
+
109
+ # Returns the maximum length of the resulting digest.
110
+ #
111
+ # @return [Number] maximum length of the resulting digest
112
+ def digest_max_length
113
+ 16
114
+ end
115
+
116
+ # Returns the name of the used authentication code algorithm.
117
+ #
118
+ # @return [String] name of the used authentication code algorithm
119
+ def name
120
+ "CMAC with #{@cipher.name[0..-9]}"
121
+ end
122
+
123
+ # Returns self as it was when it was first initialized,
124
+ # with all processed data cleared from it.
125
+ #
126
+ # @return [Object] self with initial state
127
+ def reset
128
+ @keys.clear
129
+ @buffer.clear
130
+ @cipher.reset
131
+ @cipher.encrypt
132
+ self
133
+ end
134
+
135
+ # Returns self updated with the message to be authenticated.
136
+ # Can be called repeatedly with chunks of the message.
137
+ #
138
+ # @param data [String] binary data string
139
+ #
140
+ # @return [Object] self with new state
141
+ def update(data)
142
+ fail CMACError, 'no key is set' if @keys[0].nil?
143
+
144
+ @buffer += data
145
+ @cipher.update(@buffer.slice!(0...16)) while @buffer.length > 16
146
+ self
147
+ end
148
+
149
+ # Returns the authentication code an instance represents as a binary string.
150
+ #
151
+ # @param length [Number] length of the authentication code
152
+ def digest(length = 16)
153
+ fail CMACError, 'no key is set' if @keys[0].nil?
154
+ fail CMACError, 'no key is set' unless length.between?(1, 16)
155
+
156
+ block = @buffer.bytes
157
+ @buffer.clear
158
+ k = @keys[block.length == 16 ? 1 : 2].dup
159
+ i = block.length.times { |t| k[t] ^= block[t] }
160
+ k[i] ^= 0x80 if i < 16
161
+ mac = @cipher.update(k.pack('C*'))
162
+ @cipher.reset
163
+ @cipher.encrypt
164
+ @cipher.key = @keys[0]
165
+ mac[0...length]
166
+ end
167
+ end
168
+ end
data/test/test_cmac.rb ADDED
@@ -0,0 +1,163 @@
1
+ require 'coveralls'
2
+ Coveralls.wear!
3
+ require 'test/unit'
4
+ require 'openssl/cmac'
5
+
6
+ # Testclass with Test Vectors from RFC's
7
+ class CMACTest < Test::Unit::TestCase
8
+ # http://tools.ietf.org/html/rfc4493#section-4
9
+ KEY = ['2b7e151628aed2a6abf7158809cf4f3c'].pack('H*')
10
+ DATA = [[''].pack('H*'),
11
+ ['6bc1bee22e409f96e93d7e117393172a'].pack('H*'),
12
+ ['6bc1bee22e409f96e93d7e117393172a'\
13
+ 'ae2d8a571e03ac9c9eb76fac45af8e51'\
14
+ '30c81c46a35ce411'].pack('H*'),
15
+ ['6bc1bee22e409f96e93d7e117393172a'\
16
+ 'ae2d8a571e03ac9c9eb76fac45af8e51'\
17
+ '30c81c46a35ce411e5fbc1191a0a52ef'\
18
+ 'f69f2445df4f9b17ad2b417be66c3710'].pack('H*')]
19
+ MAC = %w(bb1d6929e95937287fa37d129b756746
20
+ 070a16b46b4d4144f79bdd9dd04a287c
21
+ dfa66747de9ae63030ca32611497c827
22
+ 51f0bebf7e3b9d92fc49741779363cfe)
23
+
24
+ # http://tools.ietf.org/html/rfc4615#section-4
25
+ PRF_KEYS = [['000102030405060708090a0b0c0d0e0fedcb'].pack('H*'),
26
+ ['000102030405060708090a0b0c0d0e0f'].pack('H*'),
27
+ ['00010203040506070809'].pack('H*')]
28
+ PRF_DATA = ['000102030405060708090a0b0c0d0e0f10111213'].pack('H*')
29
+ PRF_OUTS = %w(84a348a4a45d235babfffc0d2b4da09a
30
+ 980ae87b5f4c9c5214f5b6a8455e4c2d
31
+ 290d9e112edb09ee141fcf64c0b72f3d)
32
+
33
+ def test_cmac_keys
34
+ cmac = OpenSSL::CMAC.new('AES')
35
+ cmac.key = KEY
36
+ check_keys(cmac)
37
+
38
+ cmac = OpenSSL::CMAC.new('AES', KEY)
39
+ check_keys(cmac)
40
+
41
+ assert(cmac.instance_variable_get(:@buffer).empty?, 'Wrong buffer')
42
+ cmac.update(DATA[2])
43
+ assert(cmac.instance_variable_get(:@buffer).length == 8, 'Wrong buffer')
44
+ cmac.update(DATA[2])
45
+ assert(cmac.instance_variable_get(:@buffer).length == 16, 'Wrong buffer')
46
+
47
+ cmac.reset
48
+ assert(cmac.instance_variable_get(:@keys)[0].nil?, 'Reset fail')
49
+ assert(cmac.instance_variable_get(:@keys)[1].nil?, 'Reset fail')
50
+ assert(cmac.instance_variable_get(:@keys)[2].nil?, 'Reset fail')
51
+ assert_equal('', cmac.instance_variable_get(:@buffer), 'Reset fail')
52
+
53
+ assert_raise(OpenSSL::CMACError) { cmac.update(DATA[2]) }
54
+ assert_raise(OpenSSL::CMACError) { cmac.digest }
55
+
56
+ cmac.key = KEY
57
+ check_keys(cmac)
58
+
59
+ m = cmac.update(DATA[2]).digest.unpack('H*')[0]
60
+ assert_equal(MAC[2], m)
61
+ end
62
+
63
+ def check_keys(cmac)
64
+ assert_equal(
65
+ '2b7e151628aed2a6abf7158809cf4f3c',
66
+ cmac.instance_variable_get(:@keys)[0].unpack('H*')[0],
67
+ 'Key ERROR'
68
+ )
69
+ assert_equal(
70
+ 'fbeed618357133667c85e08f7236a8de',
71
+ cmac.instance_variable_get(:@keys)[1].pack('C*').unpack('H*')[0],
72
+ 'SubKey 1 ERROR'
73
+ )
74
+
75
+ assert_equal(
76
+ 'f7ddac306ae266ccf90bc11ee46d513b',
77
+ cmac.instance_variable_get(:@keys)[2].pack('C*').unpack('H*')[0],
78
+ 'SubKey 2 ERROR'
79
+ )
80
+ end
81
+
82
+ def test_cmac_vars
83
+ cmac = OpenSSL::CMAC.new('AES')
84
+ assert_equal(16, cmac.block_length)
85
+ assert_equal(16, cmac.digest_max_length)
86
+ assert_equal('CMAC with AES', cmac.name)
87
+ end
88
+
89
+ def test_cmac_update
90
+ # Test with 1 call of update and new CCM object for each test.
91
+ DATA.length.times do |i|
92
+ cmac = OpenSSL::CMAC.new('AES', KEY)
93
+ m = cmac.update(DATA[i]).digest.unpack('H*')[0]
94
+ assert_equal(MAC[i], m, "Test: 1, Vector: #{i + 1}")
95
+ end
96
+
97
+ # Test with 1 call of update and same CCM object for each test.
98
+ # There is no reset, because it should be possible to calculate
99
+ # a new mac after digest without reset.
100
+ cmac = OpenSSL::CMAC.new('AES', KEY)
101
+ DATA.length.times do |i|
102
+ m = cmac.update(DATA[i]).digest.unpack('H*')[0]
103
+ assert_equal(MAC[i], m, "Test: 2, Vector: #{i + 1}")
104
+ end
105
+
106
+ # Test with multiple calls of update and new CCM object for each test
107
+ 1.upto(DATA.length - 1) do |i|
108
+ 1.upto(17) do |c|
109
+ cmac = OpenSSL::CMAC.new('AES', KEY)
110
+ DATA[i].bytes.each_slice(c) { |w| cmac.update(w.pack('C*')) }
111
+ m = cmac.digest.unpack('H*')[0]
112
+ assert_equal(MAC[i], m, "Test: 3, Vector: #{i + 1}, Tokenlen: #{c}")
113
+ end
114
+ end
115
+
116
+ # Test with multiple calls of update and same CCM object for each test
117
+ cmac = OpenSSL::CMAC.new('AES', KEY)
118
+ 1.upto(DATA.length - 1) do |i|
119
+ 1.upto(17) do |c|
120
+ DATA[i].bytes.each_slice(c) { |w| cmac.update(w.pack('C*')) }
121
+ m = cmac.digest.unpack('H*')[0]
122
+ assert_equal(MAC[i], m, "Test: 4, Vector: #{i + 1}, Tokenlen: #{c}")
123
+ end
124
+ end
125
+
126
+ # Test for Operator <<
127
+ DATA[3].bytes.each_slice(5) { |w| cmac << w.pack('C*') }
128
+ m = cmac.digest.unpack('H*')[0]
129
+ assert_equal(MAC[3], m, 'Test: 5, Vector: 4, Tokenlen: 5')
130
+ end
131
+
132
+ def test_cmac_digest
133
+ cmac = OpenSSL::CMAC.new('AES', KEY)
134
+ m = cmac.update(DATA[3]).digest.unpack('H*')[0]
135
+ assert_equal(MAC[3], m, 'Digest with no update')
136
+
137
+ cmac.update(DATA[3].b[0...20])
138
+ m = cmac.update(DATA[3].b[20...64]).digest.unpack('H*')[0]
139
+ assert_equal(MAC[3], m, 'Digest after update')
140
+
141
+ cmac.update(DATA[3])
142
+ m = cmac.update('').digest.unpack('H*')[0]
143
+ assert_equal(MAC[3], m, 'Empty digest')
144
+
145
+ DATA.length.times do |i|
146
+ m = OpenSSL::CMAC.digest('AES', KEY, DATA[i]).unpack('H*')[0]
147
+ assert_equal(MAC[i], m, "Vector: #{i + 1}")
148
+
149
+ m = OpenSSL::CMAC.digest('AES', KEY, DATA[i], 12).unpack('H*')[0]
150
+ assert_equal(24, m.length, "Vector: #{i + 1} - length")
151
+ assert_equal(MAC[i][0...24], m, "Vector: #{i + 1} - 12")
152
+ end
153
+ end
154
+
155
+ def test_cmac_prf
156
+ cmac = OpenSSL::CMAC.new('AES')
157
+ 3.times do |i|
158
+ cmac.key = PRF_KEYS[i]
159
+ m = cmac.update(PRF_DATA).digest.unpack('H*')[0]
160
+ assert_equal(PRF_OUTS[i], m, "Vector: #{i + 1}")
161
+ end
162
+ end
163
+ end
metadata CHANGED
@@ -1,46 +1,161 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openssl-cmac
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
5
- prerelease:
4
+ version: 2.0.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Maxim M. Chechel
8
+ - Lars Schmertmann
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-03-04 00:00:00.000000000 Z
13
- dependencies: []
14
- description: http://tools.ietf.org/html/rfc4493
15
- email: maximchick@gmail.com
12
+ date: 2014-04-02 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '10.2'
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 10.2.2
24
+ type: :development
25
+ prerelease: false
26
+ version_requirements: !ruby/object:Gem::Requirement
27
+ requirements:
28
+ - - "~>"
29
+ - !ruby/object:Gem::Version
30
+ version: '10.2'
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 10.2.2
34
+ - !ruby/object:Gem::Dependency
35
+ name: rdoc
36
+ requirement: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '4.1'
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 4.1.1
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - "~>"
49
+ - !ruby/object:Gem::Version
50
+ version: '4.1'
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: 4.1.1
54
+ - !ruby/object:Gem::Dependency
55
+ name: yard
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '0.8'
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: 0.8.7.3
64
+ type: :development
65
+ prerelease: false
66
+ version_requirements: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - "~>"
69
+ - !ruby/object:Gem::Version
70
+ version: '0.8'
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: 0.8.7.3
74
+ - !ruby/object:Gem::Dependency
75
+ name: rubocop
76
+ requirement: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - "~>"
79
+ - !ruby/object:Gem::Version
80
+ version: '0.18'
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: 0.18.1
84
+ type: :development
85
+ prerelease: false
86
+ version_requirements: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - "~>"
89
+ - !ruby/object:Gem::Version
90
+ version: '0.18'
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: 0.18.1
94
+ - !ruby/object:Gem::Dependency
95
+ name: coveralls
96
+ requirement: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - "~>"
99
+ - !ruby/object:Gem::Version
100
+ version: '0.7'
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: 0.7.0
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.7'
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: 0.7.0
114
+ description: Ruby Gem for RFC 4493, 4494, 4615 - The AES-CMAC Algorithm
115
+ email:
116
+ - maximchick@gmail.com
117
+ - SmallLars@t-online.de
16
118
  executables: []
17
119
  extensions: []
18
- extra_rdoc_files: []
120
+ extra_rdoc_files:
121
+ - README.md
122
+ - LICENSE
19
123
  files:
20
- - lib/openssl_cmac.rb
21
- homepage: https://github.com/maximchick/openssl-cmac
124
+ - ".rubocop.yml"
125
+ - ".yardopts"
126
+ - Gemfile
127
+ - LICENSE
128
+ - README.md
129
+ - Rakefile
130
+ - lib/openssl/cmac.rb
131
+ - lib/openssl/cmac/version.rb
132
+ - test/test_cmac.rb
133
+ homepage: https://github.com/smalllars/openssl-cmac
22
134
  licenses:
23
135
  - MIT
24
- post_install_message:
25
- rdoc_options: []
136
+ metadata: {}
137
+ post_install_message: Thanks for installing!
138
+ rdoc_options:
139
+ - "-x"
140
+ - test/data_*
26
141
  require_paths:
27
142
  - lib
28
143
  required_ruby_version: !ruby/object:Gem::Requirement
29
- none: false
30
144
  requirements:
31
- - - ! '>='
145
+ - - ">="
32
146
  - !ruby/object:Gem::Version
33
- version: '0'
147
+ version: 2.0.0
34
148
  required_rubygems_version: !ruby/object:Gem::Requirement
35
- none: false
36
149
  requirements:
37
- - - ! '>='
150
+ - - ">="
38
151
  - !ruby/object:Gem::Version
39
152
  version: '0'
40
153
  requirements: []
41
154
  rubyforge_project:
42
- rubygems_version: 1.8.25
155
+ rubygems_version: 2.2.2
43
156
  signing_key:
44
- specification_version: 3
45
- summary: AES-CMAC algorithm implementation
46
- test_files: []
157
+ specification_version: 4
158
+ summary: RFC 4493, 4494, 4615 - CMAC
159
+ test_files:
160
+ - test/test_cmac.rb
161
+ has_rdoc:
data/lib/openssl_cmac.rb DELETED
@@ -1,69 +0,0 @@
1
- # This is an implementation of AES-CMAC Algorithm:
2
- # http://tools.ietf.org/html/rfc4493
3
- #
4
- # OpenSSL version > 1.0.1 already has a native implementation of CMAC
5
- # but there are no corresponding bindings in Ruby OpenSSL standard library
6
-
7
- require 'openssl'
8
-
9
- module OpenSSL
10
- class CMAC
11
- CONST_ZERO = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".force_encoding('ASCII-8BIT')
12
- CONST_RB = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x87]
13
-
14
- # key - base 128 bit AES key
15
- def initialize(key)
16
- @key = key
17
- @k1, @k2 = CMAC.gen_subkeys(@key)
18
- end
19
-
20
- def generate(data)
21
- data8 = data.dup.force_encoding('ASCII-8BIT')
22
-
23
- xor_key = @k1
24
- unless data8.size > 0 && 0 == data8.size % 16
25
- xor_key = @k2
26
- padding = "\x80"
27
- padding << "\x00" * (15 - data8.size % 16)
28
- data8 << padding
29
- end
30
-
31
- data8[-16, 16].unpack('C*').each_with_index do |e, i|
32
- data8[data8.size - 16 + i] = (e ^ xor_key[i]).chr
33
- end
34
-
35
- cipher = Cipher::AES.new(128, :CBC)
36
- cipher.encrypt
37
- cipher.key = @key
38
-
39
- cipher.update(data8)[-16, 16]
40
- end
41
-
42
- def verify(data, cmac)
43
- generate(data) == cmac
44
- end
45
-
46
- def self.gen_subkeys(key)
47
- cipher = Cipher::AES.new(128, :ECB)
48
- cipher.encrypt
49
- cipher.key = key
50
-
51
- k1 = (cipher.update(CONST_ZERO)).unpack('C*')
52
- xor_flag = k1[0] >= 0x80
53
-
54
- k2 = Array.new(16)
55
-
56
- k1.each_with_index {|e, i|
57
- lsb = i == 15 ? 0 : (k1[i+1] & 0x80) / 0x80
58
- k1[i] = (k1[i] << 1) % 256 | lsb
59
- k1[i] ^= CONST_RB[i] if xor_flag
60
-
61
- lsb = i == 15 ? 0 : (k1[i+1] << 1 & 0x80) / 0x80
62
- k2[i] = (k1[i] << 1) % 256 | lsb
63
- k2[i] ^= CONST_RB[i] if k1[0] >= 0x80
64
- }
65
-
66
- [k1, k2]
67
- end
68
- end
69
- end