openssl-cmac 1.0.0 → 2.0.2

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
+ 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