openssl-cmac 1.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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