aes_key_wrap 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +3 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +33 -0
- data/Rakefile +2 -0
- data/aes_key_wrap.gemspec +23 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/lib/aes_key_wrap.rb +124 -0
- data/lib/aes_key_wrap/version.rb +3 -0
- metadata +98 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 259a4c54a9c1e9d7c04b0c5af1853702ab9762a0
|
4
|
+
data.tar.gz: c576c30659e2f1ade052b41e988ab9045fd99afd
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 491f321a2568db3fdc4e605c19eb1226163dd3f321598eb0973b295c2fa4ce5b674a7eb4f484a87eac197d425ce7a36164b3ddbcb6b46f3d4c7336b1442cba3d
|
7
|
+
data.tar.gz: 04be2bf30c6aee910095d4438a1f60be36f6f72abe1dfd4ce2788df06268dc72cc7a9ad56f50aacc2cdf59ff084392209805da82731e31009e514dcc6b5e749d
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 Tom Dalling
|
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
|
13
|
+
all 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
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# AESKeyWrap
|
2
|
+
|
3
|
+
A Ruby implementation of AES Key Wrap, a.k.a RFC 3394, a.k.a NIST Key Wrap.
|
4
|
+
|
5
|
+
## Usage
|
6
|
+
|
7
|
+
To wrap a key, call `AESKeyWrap.wrap` with:
|
8
|
+
|
9
|
+
- The plain text key
|
10
|
+
- A key-encrypting key (KEK)
|
11
|
+
- An "initial value" (optional)
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
require 'aes_key_wrap'
|
15
|
+
plaintext_key = ['00112233445566778899AABBCCDDEEFF'].pack('H*') #binary string
|
16
|
+
kek = ['000102030405060708090A0B0C0D0E0F'].pack('H*') # binary string
|
17
|
+
iv = 0xDEADBEEFC0FFEEEE
|
18
|
+
wrapped_key = AESKeyWrap.wrap(plaintext_key, kek, iv)
|
19
|
+
```
|
20
|
+
|
21
|
+
To unwrap a key, call `AESKeyWrap.unwrap`:
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
unwrapped = AESKeyWrap.unwrap(wrapped_key, kek, iv)
|
25
|
+
```
|
26
|
+
|
27
|
+
There also `unwrap!`, which throws an exception if unwrapping
|
28
|
+
fails, instead of returning nil:
|
29
|
+
|
30
|
+
## Contributing
|
31
|
+
|
32
|
+
Make sure it's got tests, then do the usual fork and pull request hooha.
|
33
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'aes_key_wrap/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'aes_key_wrap'
|
8
|
+
spec.version = AESKeyWrap::VERSION
|
9
|
+
spec.authors = ['Tom Dalling']
|
10
|
+
spec.email = ['tom' + '@tom' + 'dalling.com']
|
11
|
+
|
12
|
+
spec.summary = %q{A Ruby implementation of AES Key Wrap, a.k.a RFC 3394, a.k.a NIST Key Wrap.}
|
13
|
+
spec.homepage = 'https://github.com/tomdalling/aes_key_wrap'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
17
|
+
spec.require_paths = ['lib']
|
18
|
+
|
19
|
+
spec.add_development_dependency 'bundler', '~> 1.8'
|
20
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
21
|
+
spec.add_development_dependency 'rspec', '~> 3.2.0'
|
22
|
+
end
|
23
|
+
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "aes_key_wrap"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
data/lib/aes_key_wrap.rb
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
##
|
2
|
+
# A Ruby implementation of AES Key Wrap, a.k.a RFC 3394, a.k.a NIST Key Wrapping
|
3
|
+
#
|
4
|
+
module AESKeyWrap
|
5
|
+
DEFAULT_IV = 0xA6A6A6A6A6A6A6A6
|
6
|
+
UnwrapFailedError = Class.new(StandardError)
|
7
|
+
|
8
|
+
class << self
|
9
|
+
|
10
|
+
##
|
11
|
+
# Wraps a key using a key-encrypting key (KEK)
|
12
|
+
#
|
13
|
+
# This is an implementation of the "index based" algorithm
|
14
|
+
# specified in section 2.2.1 of RFC 3394:
|
15
|
+
# http://www.ietf.org/rfc/rfc3394.txt
|
16
|
+
#
|
17
|
+
# @param unwrapped_key [String] The plaintext key to be wrapped, as a binary string
|
18
|
+
# @param kek [String] The key-encrypting key, as a binary_string
|
19
|
+
# @param iv [Integer] The "initial value", as unsigned 64bit integer
|
20
|
+
# @return [String] The wrapped key, as a binary string
|
21
|
+
#
|
22
|
+
def wrap(unwrapped_key, kek, iv=DEFAULT_IV)
|
23
|
+
# 1) Initialize variables.
|
24
|
+
#
|
25
|
+
# P: buffer (from unwrapped_key)
|
26
|
+
# A: buffer[0]
|
27
|
+
# R: buffer
|
28
|
+
# K: kek
|
29
|
+
# n: block_count
|
30
|
+
# AES: aes(:encrypt, _, _)
|
31
|
+
# IV: iv
|
32
|
+
buffer = [iv] + unwrapped_key.unpack('Q>*')
|
33
|
+
block_count = buffer.size - 1
|
34
|
+
|
35
|
+
# 2) Calculate intermediate values.
|
36
|
+
# t: round
|
37
|
+
0.upto(5) do |j|
|
38
|
+
1.upto(block_count) do |i|
|
39
|
+
round = block_count*j + i
|
40
|
+
# In
|
41
|
+
data = [buffer[0], buffer[i]].pack('Q>2')
|
42
|
+
buffer[0], buffer[i] = aes(:encrypt, kek, data).unpack('Q>2')
|
43
|
+
# Enc
|
44
|
+
buffer[0] = buffer[0] ^ round
|
45
|
+
# XorT
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# 3) Output the results.
|
50
|
+
buffer.pack('Q>*')
|
51
|
+
end
|
52
|
+
|
53
|
+
##
|
54
|
+
# Unwraps an encrypted key using a key-encrypting key (KEK)
|
55
|
+
#
|
56
|
+
# This is an implementation of the "index based" algorithm
|
57
|
+
# specified in section 2.2.2 of RFC 3394:
|
58
|
+
# http://www.ietf.org/rfc/rfc3394.txt
|
59
|
+
#
|
60
|
+
# @param wrapped_key [String] The wrapped key (cyphertext), as a binary string
|
61
|
+
# @param kek [String] The key-encrypting key, as a binary string
|
62
|
+
# @param expected_iv [Integer] The IV used to wrap the key, as an unsigned 64bit integer
|
63
|
+
# @return [String] The unwrapped (plaintext) key as a binary string, or
|
64
|
+
# `nil` if unwrapping failed due to `expected_iv` not matching the
|
65
|
+
# decrypted IV
|
66
|
+
#
|
67
|
+
# @see #unwrap!
|
68
|
+
#
|
69
|
+
def unwrap(wrapped_key, kek, expected_iv=DEFAULT_IV)
|
70
|
+
# 1) Initialize variables.
|
71
|
+
#
|
72
|
+
# C: buffer (from wrapped_key)
|
73
|
+
# A: buffer[0]
|
74
|
+
# R: buffer
|
75
|
+
# n: block_count
|
76
|
+
# K: kek
|
77
|
+
# AES-1: aes(:decrypt, _, _)
|
78
|
+
buffer = wrapped_key.unpack('Q>*')
|
79
|
+
block_count = buffer.size - 1
|
80
|
+
|
81
|
+
# 2) Calculate intermediate values.
|
82
|
+
# t: round
|
83
|
+
5.downto(0) do |j|
|
84
|
+
block_count.downto(1) do |i|
|
85
|
+
round = block_count*j + i
|
86
|
+
# In
|
87
|
+
buffer[0] = buffer[0] ^ round
|
88
|
+
# XorT
|
89
|
+
data = [buffer[0], buffer[i]].pack('Q>2')
|
90
|
+
buffer[0], buffer[i] = aes(:decrypt, kek, data).unpack('Q>2')
|
91
|
+
# Dec
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# 3) Output the results.
|
96
|
+
if buffer[0] == expected_iv
|
97
|
+
buffer.drop(1).pack('Q>*')
|
98
|
+
else
|
99
|
+
nil
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
##
|
104
|
+
# Exception-throwing version of #unwrap
|
105
|
+
#
|
106
|
+
# @see #unwrap
|
107
|
+
#
|
108
|
+
def unwrap!(*args)
|
109
|
+
unwrap(*args) || raise(UnwrapFailedError, 'Unwrapped IV does not match')
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
def aes(encrypt_or_decrypt, key, data)
|
115
|
+
decipher = OpenSSL::Cipher::AES.new(key.bytesize * 8, :ECB)
|
116
|
+
decipher.send(encrypt_or_decrypt)
|
117
|
+
decipher.key = key
|
118
|
+
decipher.padding = 0
|
119
|
+
|
120
|
+
decipher.update(data) + decipher.final
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
metadata
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: aes_key_wrap
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tom Dalling
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-04-24 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.8'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.8'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 3.2.0
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 3.2.0
|
55
|
+
description:
|
56
|
+
email:
|
57
|
+
- tom@tomdalling.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- ".gitignore"
|
63
|
+
- ".rspec"
|
64
|
+
- ".travis.yml"
|
65
|
+
- Gemfile
|
66
|
+
- LICENSE.txt
|
67
|
+
- README.md
|
68
|
+
- Rakefile
|
69
|
+
- aes_key_wrap.gemspec
|
70
|
+
- bin/console
|
71
|
+
- bin/setup
|
72
|
+
- lib/aes_key_wrap.rb
|
73
|
+
- lib/aes_key_wrap/version.rb
|
74
|
+
homepage: https://github.com/tomdalling/aes_key_wrap
|
75
|
+
licenses:
|
76
|
+
- MIT
|
77
|
+
metadata: {}
|
78
|
+
post_install_message:
|
79
|
+
rdoc_options: []
|
80
|
+
require_paths:
|
81
|
+
- lib
|
82
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
83
|
+
requirements:
|
84
|
+
- - ">="
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: '0'
|
87
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - ">="
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '0'
|
92
|
+
requirements: []
|
93
|
+
rubyforge_project:
|
94
|
+
rubygems_version: 2.4.5
|
95
|
+
signing_key:
|
96
|
+
specification_version: 4
|
97
|
+
summary: A Ruby implementation of AES Key Wrap, a.k.a RFC 3394, a.k.a NIST Key Wrap.
|
98
|
+
test_files: []
|