openssl-cmac 1.0.0 → 2.0.2

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
+ SHA256:
3
+ metadata.gz: 16491a689fe7f5d899159d3762cd7618f3150bc2a1ecede264731ef308a5d876
4
+ data.tar.gz: b4df90a8d51cdba9649101217df4978181a93ea680ac67c3b6cd0b15939e55e7
5
+ SHA512:
6
+ metadata.gz: 0b26a6dd073ebdef048598ccec4a44ab0fe7510a785a5dc656cc28760dfa596b7f7e358abd3d1940709687dc1e4ad730348198a0bd9174df166636055715b2fc
7
+ data.tar.gz: 82292fbd9b159ca48b8062093c8a6c093960b52813717729a38648f880ad84c2b9843e91b5d42782e91ee51a38dd05288ea76b3bdbe4e8b4552667144a540d5b
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,8 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'rake', '>=12.3.2'
4
+ gem 'rdoc', '>=4.3.0'
5
+ gem 'yard', '>=0.9.16'
6
+ gem 'rubocop', '>=0.50.0'
7
+ gem 'test-unit', '>=3.2.9'
8
+ gem 'coveralls', '>=0.8.22'
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-ci.org/github/smalllars/openssl-cmac.png)](http://inch-ci.org/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 ./pkg/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.2'
4
+ end
5
+ end
@@ -0,0 +1,171 @@
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
+ @ciphers ||= OpenSSL::Cipher.ciphers.select { |c| c.match(/-128-CBC$/i) }.map { |e| e[0..-9].upcase }.uniq
30
+ end
31
+
32
+ # Returns the authentication code as a binary string. The cipher parameter
33
+ # must be an entry of OpenSSL::CMAC.ciphers.
34
+ #
35
+ # @param cipher [String] entry of OpenSSL::CMAC.ciphers
36
+ # @param key [String] binary key string
37
+ # @param data [String] binary data string
38
+ # @param length [Number] length of the authentication code
39
+ #
40
+ # @return [String] authentication code
41
+ def self.digest(cipher, key, data, length = 16)
42
+ CMAC.new(cipher, key).update(data).digest(length)
43
+ end
44
+
45
+ public
46
+
47
+ # Returns an instance of OpenSSL::CMAC set with the cipher algorithm and
48
+ # key to be used. The instance represents the initial state of the message
49
+ # authentication code before any data has been processed. To process data
50
+ # with it, use the instance method update with your data as an argument.
51
+ #
52
+ # @param cipher [String] entry of OpenSSL::CMAC.ciphers
53
+ # @param key [String] binary key string
54
+ #
55
+ # @return [Object] the new CMAC object
56
+ def initialize(cipher, key = '')
57
+ unless CMAC.ciphers.include?(cipher.upcase)
58
+ fail CMACError, "unsupported cipher algorithm (#{cipher})"
59
+ end
60
+
61
+ @keys = []
62
+ @buffer = ''.force_encoding('ASCII-8BIT')
63
+ @cipher = OpenSSL::Cipher.new("#{cipher.upcase}-128-CBC")
64
+
65
+ self.key = key unless key == ''
66
+ end
67
+
68
+ # Returns self as it was when it was first initialized with new key,
69
+ # with all processed data cleared from it.
70
+ #
71
+ # @param key [String] binary key string
72
+ #
73
+ # @return [Object] self with initial state and new key
74
+ def key=(key)
75
+ reset
76
+ key = CMAC.digest('AES', "\x00" * 16, key, 16) unless key.b.length == 16
77
+
78
+ @keys[0] = key.dup
79
+ @cipher.key = @keys[0]
80
+
81
+ cipher = OpenSSL::Cipher.new(@cipher.name)
82
+ cipher.encrypt
83
+ cipher.key = @keys[0]
84
+ k = (cipher.update("\x00" * 16) + cipher.final).bytes[0...16]
85
+ 1.upto(2) do |i|
86
+ k = k.pack('C*').unpack('B*')[0]
87
+ msb = k.slice!(0)
88
+ k = [k, '0'].pack('B*').bytes
89
+ k[15] ^= 0x87 if msb == '1'
90
+ @keys[i] = k.dup
91
+ end
92
+ self
93
+ end
94
+
95
+ # Alias for: update
96
+ def <<(data)
97
+ update(data)
98
+ end
99
+
100
+ # Returns the block length of the used cipher algorithm.
101
+ #
102
+ # @return [Number] length of the used cipher algorithm
103
+ def block_length
104
+ 16
105
+ end
106
+
107
+ # Returns the maximum length of the resulting digest.
108
+ #
109
+ # @return [Number] maximum length of the resulting digest
110
+ def digest_max_length
111
+ 16
112
+ end
113
+
114
+ # Returns the name of the used authentication code algorithm.
115
+ #
116
+ # @return [String] name of the used authentication code algorithm
117
+ def name
118
+ "CMAC with #{@cipher.name[0..-9]}"
119
+ end
120
+
121
+ # Returns self as it was when it was first initialized,
122
+ # with all processed data cleared from it.
123
+ #
124
+ # @return [Object] self with initial state
125
+ def reset
126
+ @keys.clear
127
+ @buffer.clear
128
+ @cipher.reset unless @keys[0].nil?
129
+ @cipher.iv = "\x00" * 16
130
+ @cipher.encrypt
131
+ self
132
+ end
133
+
134
+ # Returns self updated with the message to be authenticated.
135
+ # Can be called repeatedly with chunks of the message.
136
+ #
137
+ # @param data [String] binary data string
138
+ #
139
+ # @return [Object] self with new state
140
+ def update(data)
141
+ fail CMACError, 'no key is set' if @keys[0].nil?
142
+
143
+ @buffer += data
144
+ @cipher.update(@buffer.slice!(0...16)) while @buffer.length > 16
145
+ self
146
+ end
147
+
148
+ # Returns the authentication code an instance represents as a binary string.
149
+ #
150
+ # @param length [Number] length of the authentication code
151
+ def digest(length = 16)
152
+ fail CMACError, 'no key is set' if @keys[0].nil?
153
+ fail CMACError, 'no key is set' unless length.between?(1, 16)
154
+
155
+ block = @buffer.bytes
156
+ @buffer.clear
157
+ k = @keys[block.length == 16 ? 1 : 2].dup
158
+ i = block.length.times { |t| k[t] ^= block[t] }
159
+ k[i] ^= 0x80 if i < 16
160
+ mac = @cipher.update(k.pack('C*')) + @cipher.final
161
+ @cipher.reset
162
+ @cipher.encrypt
163
+ @cipher.key = @keys[0]
164
+ @cipher.iv = "\x00" * 16
165
+ # Each block is 16-bytes and the last block will always be PKCS#7 padding
166
+ # which we want to discard. Take the last block prior to the padding for
167
+ # the MAC.
168
+ mac[-32...(-32 + length)]
169
+ end
170
+ end
171
+ end
data/test/test_cmac.rb ADDED
@@ -0,0 +1,167 @@
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
+ for cipher in ['aes', 'AES']
91
+ # Test with 1 call of update and new CCM object for each test.
92
+ DATA.length.times do |i|
93
+ cmac = OpenSSL::CMAC.new(cipher, KEY)
94
+ m = cmac.update(DATA[i]).digest.unpack('H*')[0]
95
+ assert_equal(MAC[i], m, "Test: 1, Vector: #{i + 1}")
96
+ end
97
+
98
+ # Test with 1 call of update and same CCM object for each test.
99
+ # There is no reset, because it should be possible to calculate
100
+ # a new mac after digest without reset.
101
+ cmac = OpenSSL::CMAC.new(cipher, KEY)
102
+ DATA.length.times do |i|
103
+ m = cmac.update(DATA[i]).digest.unpack('H*')[0]
104
+ assert_equal(MAC[i], m, "Test: 2, Vector: #{i + 1}")
105
+ end
106
+
107
+ # Test with multiple calls of update and new CCM object for each test
108
+ 1.upto(DATA.length - 1) do |i|
109
+ 1.upto(17) do |c|
110
+ cmac = OpenSSL::CMAC.new(cipher, KEY)
111
+ DATA[i].bytes.each_slice(c) { |w| cmac.update(w.pack('C*')) }
112
+ m = cmac.digest.unpack('H*')[0]
113
+ assert_equal(MAC[i], m, "Test: 3, Vector: #{i + 1}, Tokenlen: #{c}")
114
+ end
115
+ end
116
+
117
+ # Test with multiple calls of update and same CCM object for each test
118
+ cmac = OpenSSL::CMAC.new(cipher, KEY)
119
+ 1.upto(DATA.length - 1) do |i|
120
+ 1.upto(17) do |c|
121
+ DATA[i].bytes.each_slice(c) { |w| cmac.update(w.pack('C*')) }
122
+ m = cmac.digest.unpack('H*')[0]
123
+ assert_equal(MAC[i], m, "Test: 4, Vector: #{i + 1}, Tokenlen: #{c}")
124
+ end
125
+ end
126
+ end
127
+
128
+ # Test for Operator <<
129
+ DATA[3].bytes.each_slice(5) { |w| cmac << w.pack('C*') }
130
+ m = cmac.digest.unpack('H*')[0]
131
+ assert_equal(MAC[3], m, 'Test: 5, Vector: 4, Tokenlen: 5')
132
+ end
133
+
134
+ def test_cmac_digest
135
+ for cipher in ['aes', 'AES']
136
+ cmac = OpenSSL::CMAC.new(cipher, KEY)
137
+ m = cmac.update(DATA[3]).digest.unpack('H*')[0]
138
+ assert_equal(MAC[3], m, 'Digest with no update')
139
+
140
+ cmac.update(DATA[3].b[0...20])
141
+ m = cmac.update(DATA[3].b[20...64]).digest.unpack('H*')[0]
142
+ assert_equal(MAC[3], m, 'Digest after update')
143
+
144
+ cmac.update(DATA[3])
145
+ m = cmac.update('').digest.unpack('H*')[0]
146
+ assert_equal(MAC[3], m, 'Empty digest')
147
+
148
+ DATA.length.times do |i|
149
+ m = OpenSSL::CMAC.digest(cipher, KEY, DATA[i]).unpack('H*')[0]
150
+ assert_equal(MAC[i], m, "Vector: #{i + 1}")
151
+
152
+ m = OpenSSL::CMAC.digest(cipher, KEY, DATA[i], 12).unpack('H*')[0]
153
+ assert_equal(24, m.length, "Vector: #{i + 1} - length")
154
+ assert_equal(MAC[i][0...24], m, "Vector: #{i + 1} - 12")
155
+ end
156
+ end
157
+ end
158
+
159
+ def test_cmac_prf
160
+ cmac = OpenSSL::CMAC.new('AES')
161
+ 3.times do |i|
162
+ cmac.key = PRF_KEYS[i]
163
+ m = cmac.update(PRF_DATA).digest.unpack('H*')[0]
164
+ assert_equal(PRF_OUTS[i], m, "Vector: #{i + 1}")
165
+ end
166
+ end
167
+ end
metadata CHANGED
@@ -1,46 +1,179 @@
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.2
6
5
  platform: ruby
7
6
  authors:
8
7
  - Maxim M. Chechel
9
- autorequire:
8
+ - Lars Schmertmann
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: 2022-07-29 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: '12.3'
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 12.3.2
24
+ type: :development
25
+ prerelease: false
26
+ version_requirements: !ruby/object:Gem::Requirement
27
+ requirements:
28
+ - - "~>"
29
+ - !ruby/object:Gem::Version
30
+ version: '12.3'
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 12.3.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.3'
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 4.3.0
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - "~>"
49
+ - !ruby/object:Gem::Version
50
+ version: '4.3'
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: 4.3.0
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.9'
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: 0.9.16
64
+ type: :development
65
+ prerelease: false
66
+ version_requirements: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - "~>"
69
+ - !ruby/object:Gem::Version
70
+ version: '0.9'
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: 0.9.16
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.50'
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: 0.50.0
84
+ type: :development
85
+ prerelease: false
86
+ version_requirements: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - "~>"
89
+ - !ruby/object:Gem::Version
90
+ version: '0.50'
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: 0.50.0
94
+ - !ruby/object:Gem::Dependency
95
+ name: test-unit
96
+ requirement: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - "~>"
99
+ - !ruby/object:Gem::Version
100
+ version: '3.2'
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: 3.2.9
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '3.2'
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: 3.2.9
114
+ - !ruby/object:Gem::Dependency
115
+ name: coveralls
116
+ requirement: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - "~>"
119
+ - !ruby/object:Gem::Version
120
+ version: '0.8'
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: 0.8.22
124
+ type: :development
125
+ prerelease: false
126
+ version_requirements: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - "~>"
129
+ - !ruby/object:Gem::Version
130
+ version: '0.8'
131
+ - - ">="
132
+ - !ruby/object:Gem::Version
133
+ version: 0.8.22
134
+ description: Ruby Gem for RFC 4493, 4494, 4615 - The AES-CMAC Algorithm
135
+ email:
136
+ - maximchick@gmail.com
137
+ - SmallLars@t-online.de
16
138
  executables: []
17
139
  extensions: []
18
- extra_rdoc_files: []
140
+ extra_rdoc_files:
141
+ - README.md
142
+ - LICENSE
19
143
  files:
20
- - lib/openssl_cmac.rb
21
- homepage: https://github.com/maximchick/openssl-cmac
144
+ - ".rubocop.yml"
145
+ - ".yardopts"
146
+ - Gemfile
147
+ - LICENSE
148
+ - README.md
149
+ - Rakefile
150
+ - lib/openssl/cmac.rb
151
+ - lib/openssl/cmac/version.rb
152
+ - test/test_cmac.rb
153
+ homepage: https://github.com/smalllars/openssl-cmac
22
154
  licenses:
23
155
  - MIT
24
- post_install_message:
25
- rdoc_options: []
156
+ metadata: {}
157
+ post_install_message: Thanks for installing!
158
+ rdoc_options:
159
+ - "-x"
160
+ - test/data_*
26
161
  require_paths:
27
162
  - lib
28
163
  required_ruby_version: !ruby/object:Gem::Requirement
29
- none: false
30
164
  requirements:
31
- - - ! '>='
165
+ - - ">="
32
166
  - !ruby/object:Gem::Version
33
- version: '0'
167
+ version: 2.0.0
34
168
  required_rubygems_version: !ruby/object:Gem::Requirement
35
- none: false
36
169
  requirements:
37
- - - ! '>='
170
+ - - ">="
38
171
  - !ruby/object:Gem::Version
39
172
  version: '0'
40
173
  requirements: []
41
- rubyforge_project:
42
- rubygems_version: 1.8.25
43
- signing_key:
44
- specification_version: 3
45
- summary: AES-CMAC algorithm implementation
46
- test_files: []
174
+ rubygems_version: 3.3.15
175
+ signing_key:
176
+ specification_version: 4
177
+ summary: RFC 4493, 4494, 4615 - CMAC
178
+ test_files:
179
+ - test/test_cmac.rb
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