aes-key-wrap-1.0.1/0000755000175000017500000000000013335052410013036 5ustar pravipraviaes-key-wrap-1.0.1/README.md0000644000175000017500000000163513335052410014322 0ustar pravipravi[![Build Status](https://travis-ci.org/tomdalling/aes_key_wrap.svg?branch=master)](https://travis-ci.org/tomdalling/aes_key_wrap) # AESKeyWrap A Ruby implementation of AES Key Wrap, a.k.a RFC 3394, a.k.a NIST Key Wrap. ## Usage To wrap a key, call `AESKeyWrap.wrap` with: - The plain text key - A key-encrypting key (KEK) - An "initial value" (optional) ```ruby require 'aes_key_wrap' plaintext_key = ['00112233445566778899AABBCCDDEEFF'].pack('H*') #binary string kek = ['000102030405060708090A0B0C0D0E0F'].pack('H*') # binary string iv = 0xDEADBEEFC0FFEEEE wrapped_key = AESKeyWrap.wrap(plaintext_key, kek, iv) ``` To unwrap a key, call `AESKeyWrap.unwrap`: ```ruby unwrapped = AESKeyWrap.unwrap(wrapped_key, kek, iv) ``` There also `unwrap!`, which throws an exception if unwrapping fails, instead of returning nil. ## Contributing Make sure it's got tests, then do the usual fork and pull request hooha. aes-key-wrap-1.0.1/aes_key_wrap.gemspec0000644000175000017500000000144613335052410017061 0ustar pravipravi# coding: utf-8 lib = File.expand_path('../lib', __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'aes_key_wrap/version' Gem::Specification.new do |spec| spec.name = 'aes_key_wrap' spec.version = AESKeyWrap::VERSION spec.authors = ['Tom Dalling'] spec.email = ['tom' + '@tom' + 'dalling.com'] spec.summary = %q{A Ruby implementation of AES Key Wrap, a.k.a RFC 3394, a.k.a NIST Key Wrap.} spec.homepage = 'https://github.com/tomdalling/aes_key_wrap' spec.license = 'MIT' spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } spec.require_paths = ['lib'] spec.add_development_dependency 'rake', '~> 10.0' spec.add_development_dependency 'rspec', '~> 3.2.0' end aes-key-wrap-1.0.1/lib/0000755000175000017500000000000013335052410013604 5ustar pravipraviaes-key-wrap-1.0.1/lib/aes_key_wrap.rb0000644000175000017500000000705213335052410016606 0ustar pravipravirequire 'openssl' ## # A Ruby implementation of AES Key Wrap, a.k.a RFC 3394, a.k.a NIST Key Wrapping # module AESKeyWrap DEFAULT_IV = 0xA6A6A6A6A6A6A6A6 UnwrapFailedError = Class.new(StandardError) class << self ## # Wraps a key using a key-encrypting key (KEK) # # This is an implementation of the "index based" algorithm # specified in section 2.2.1 of RFC 3394: # http://www.ietf.org/rfc/rfc3394.txt # # @param unwrapped_key [String] The plaintext key to be wrapped, as a binary string # @param kek [String] The key-encrypting key, as a binary_string # @param iv [Integer] The "initial value", as unsigned 64bit integer # @return [String] The wrapped key, as a binary string # def wrap(unwrapped_key, kek, iv=DEFAULT_IV) # 1) Initialize variables. # # P: buffer (from unwrapped_key) # A: buffer[0] # R: buffer # K: kek # n: block_count # AES: aes(:encrypt, _, _) # IV: iv buffer = [iv] + unwrapped_key.unpack('Q>*') block_count = buffer.size - 1 # 2) Calculate intermediate values. # t: round 0.upto(5) do |j| 1.upto(block_count) do |i| round = block_count*j + i # In data = [buffer[0], buffer[i]].pack('Q>2') buffer[0], buffer[i] = aes(:encrypt, kek, data).unpack('Q>2') # Enc buffer[0] = buffer[0] ^ round # XorT end end # 3) Output the results. buffer.pack('Q>*') end ## # Unwraps an encrypted key using a key-encrypting key (KEK) # # This is an implementation of the "index based" algorithm # specified in section 2.2.2 of RFC 3394: # http://www.ietf.org/rfc/rfc3394.txt # # @param wrapped_key [String] The wrapped key (cyphertext), as a binary string # @param kek [String] The key-encrypting key, as a binary string # @param expected_iv [Integer] The IV used to wrap the key, as an unsigned 64bit integer # @return [String] The unwrapped (plaintext) key as a binary string, or # `nil` if unwrapping failed due to `expected_iv` not matching the # decrypted IV # # @see #unwrap! # def unwrap(wrapped_key, kek, expected_iv=DEFAULT_IV) # 1) Initialize variables. # # C: buffer (from wrapped_key) # A: buffer[0] # R: buffer # n: block_count # K: kek # AES-1: aes(:decrypt, _, _) buffer = wrapped_key.unpack('Q>*') block_count = buffer.size - 1 # 2) Calculate intermediate values. # t: round 5.downto(0) do |j| block_count.downto(1) do |i| round = block_count*j + i # In buffer[0] = buffer[0] ^ round # XorT data = [buffer[0], buffer[i]].pack('Q>2') buffer[0], buffer[i] = aes(:decrypt, kek, data).unpack('Q>2') # Dec end end # 3) Output the results. if buffer[0] == expected_iv buffer.drop(1).pack('Q>*') else nil end end ## # Exception-throwing version of #unwrap # # @see #unwrap # def unwrap!(*args) unwrap(*args) || raise(UnwrapFailedError, 'Unwrapped IV does not match') end private def aes(encrypt_or_decrypt, key, data) decipher = OpenSSL::Cipher::AES.new(key.bytesize * 8, :ECB) decipher.send(encrypt_or_decrypt) decipher.key = key decipher.padding = 0 decipher.update(data) + decipher.final end end end aes-key-wrap-1.0.1/lib/aes_key_wrap/0000755000175000017500000000000013335052410016255 5ustar pravipraviaes-key-wrap-1.0.1/lib/aes_key_wrap/version.rb0000644000175000017500000000005213335052410020264 0ustar pravipravimodule AESKeyWrap VERSION = '1.0.1' end aes-key-wrap-1.0.1/.travis.yml0000644000175000017500000000001713335052410015145 0ustar pravipravilanguage: ruby aes-key-wrap-1.0.1/LICENSE.txt0000644000175000017500000000206613335052410014665 0ustar pravipraviThe MIT License (MIT) Copyright (c) 2015 Tom Dalling Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. aes-key-wrap-1.0.1/.gitignore0000644000175000017500000000012713335052410015026 0ustar pravipravi/.bundle/ /.yardoc /Gemfile.lock /_yardoc/ /coverage/ /doc/ /pkg/ /spec/reports/ /tmp/ aes-key-wrap-1.0.1/Rakefile0000644000175000017500000000022413335052410014501 0ustar pravipravirequire "bundler/gem_tasks" begin require 'rspec/core/rake_task' RSpec::Core::RakeTask.new(:spec) rescue LoadError end task :default => :spec aes-key-wrap-1.0.1/Gemfile0000644000175000017500000000014113335052410014325 0ustar pravipravisource 'https://rubygems.org' # Specify your gem's dependencies in aes_key_wrap.gemspec gemspec aes-key-wrap-1.0.1/.rspec0000644000175000017500000000003713335052410014153 0ustar pravipravi--format documentation --color aes-key-wrap-1.0.1/.ruby-version0000644000175000017500000000000613335052410015477 0ustar pravipravi2.2.0 aes-key-wrap-1.0.1/bin/0000755000175000017500000000000013335052410013606 5ustar pravipraviaes-key-wrap-1.0.1/bin/setup0000755000175000017500000000016313335052410014674 0ustar pravipravi#!/bin/bash set -euo pipefail IFS=$'\n\t' bundle install # Do any other automated setup that you need to do here aes-key-wrap-1.0.1/bin/console0000755000175000017500000000052113335052410015174 0ustar pravipravi#!/usr/bin/env ruby require "bundler/setup" require "aes_key_wrap" # You can add fixtures and/or initialization code here to make experimenting # with your gem easier. You can also use a different console, if you like. # (If you use this, don't forget to add pry to your Gemfile!) # require "pry" # Pry.start require "irb" IRB.start