Skip to content
Browse files

Incorporate Krypt and wire it up for OpenSSL::PKCS5.

  • Loading branch information...
1 parent c554ce2 commit cc9acbaf23ac5d1bcf26d9e304f2360300cfe10e @headius headius committed
View
39 lib/ruby/shared/krypt-core.rb
@@ -0,0 +1,39 @@
+=begin
+
+= Info
+
+krypt-core API - Java implementation
+
+Copyright (C) 2011-2013
+Hiroshi Nakamura <nahi@ruby-lang.org>
+Martin Bosslet <martin.bosslet@gmail.com>
+All rights reserved.
+
+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.
+
+=end
+
+unless defined? JRUBY_VERSION
+ warn 'Loading krypt-core-java in a non-JRuby interpreter'
+end
+
+require 'kryptcore.jar'
+require 'krypt-provider-jdk'
+
View
33 lib/ruby/shared/krypt-provider-jdk.rb
@@ -0,0 +1,33 @@
+=begin
+
+= Info
+
+krypt-provider-jdk - Implementation using the JDK security library
+
+Copyright (C) 2011-2013
+Hiroshi Nakamura <nahi@ruby-lang.org>
+Martin Bosslet <martin.bosslet@gmail.com>
+All rights reserved.
+
+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.
+
+=end
+
+require 'kryptproviderjdk.jar'
View
49 lib/ruby/shared/krypt.rb
@@ -0,0 +1,49 @@
+=begin
+
+= Info
+
+krypt - Modern platform- and library-independent cryptography for Ruby
+
+Copyright (C) 2011-2013
+Hiroshi Nakamura <nahi@ruby-lang.org>
+Martin Bosslet <martin.bosslet@gmail.com>
+All rights reserved.
+
+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.
+
+=end
+
+module Krypt
+ class Error < StandardError; end
+end
+
+require_relative 'krypt_missing'
+require_relative 'krypt/provider'
+require_relative 'krypt/digest'
+require_relative 'krypt/hmac'
+require_relative 'krypt/pkcs5'
+
+require 'krypt-core'
+
+# The following files depend on krypt-core being loaded
+require_relative 'krypt/asn1'
+require_relative 'krypt/x509'
+require_relative 'krypt/codec'
+
View
3 lib/ruby/shared/krypt/asn1.rb
@@ -0,0 +1,3 @@
+require_relative 'asn1/template'
+require_relative 'asn1/common'
+
View
96 lib/ruby/shared/krypt/asn1/common.rb
@@ -0,0 +1,96 @@
+module Krypt
+ module ASN1
+
+ class DirectoryString
+ include Template::Choice
+
+ asn1_t61_string
+ asn1_ia5_string
+ asn1_printable_string
+ asn1_universal_string
+ asn1_utf8_string
+ asn1_bmp_string
+ end
+
+ class DistinguishedName
+ include Template::SequenceOf
+
+ class AttributeTypeAndValue
+ include Template::Sequence
+
+ asn1_object_id :type
+ asn1_template :value, DirectoryString
+ end
+
+ class RelativeDistinguishedName
+ include Template::SetOf
+
+ asn1_type AttributeTypeAndValue
+ end
+
+ asn1_type RelativeDistinguishedName
+ end
+
+ class GeneralName
+ include Template::Choice
+
+ class OtherName
+ include Template::Sequence
+
+ asn1_object_id :type
+ asn1_any :value, tag: 0, tagging: :EXPLICIT
+ end
+
+ class EDIPartyName
+ include Template::Sequence
+
+ asn1_template :name_assigner, DirectoryString, tag: 0, tagging: :IMPLICIT, optional: true
+ asn1_template :party_name, DirectoryString, tag: 1, tagging: :IMPLICIT
+ end
+
+ asn1_template OtherName, tag: 0, tagging: :IMPLICIT
+ asn1_ia5_string tag: 1, tagging: :IMPLICIT
+ asn1_ia5_string tag: 2, tagging: :IMPLICIT
+ asn1_any tag: 3, tagging: :IMPLICIT
+ asn1_template DistinguishedName, tag: 4, tagging: :EXPLICIT
+ asn1_template EDIPartyName, tag: 5, tagging: :IMPLICIT
+ asn1_ia5_string tag: 6, tagging: :IMPLICIT
+ asn1_octet_string tag: 7, tagging: :IMPLICIT
+ asn1_object_id tag: 8, tagging: :IMPLICIT
+ end
+
+ class AlgorithmIdentifier
+ include Template::Sequence
+
+ asn1_object_id :algorithm
+ asn1_any :params, optional: true
+
+ def self.algorithm_null_params(name)
+ AlgorithmIdentifier.new do |alg|
+ alg.algorithm = name
+ alg.params = Krypt::ASN1::Null.new
+ end
+ end
+ class << self; private :algorithm_null_params; end
+
+ MD5 = algorithm_null_params('1.2.840.113549.2.5')
+ RIPEMD160 = algorithm_null_params('1.3.36.3.2.1')
+ SHA1 = algorithm_null_params('1.3.14.3.2.26')
+ SHA224 = algorithm_null_params('2.16.840.1.101.3.4.2.4')
+ SHA256 = algorithm_null_params('2.16.840.1.101.3.4.2.1')
+ SHA384 = algorithm_null_params('2.16.840.1.101.3.4.2.2')
+ SHA512 = algorithm_null_params('2.16.840.1.101.3.4.2.3')
+
+ RSA = algorithm_null_params('1.2.840.113549.1.1.1')
+
+ RSA_MD5 = algorithm_null_params('1.2.840.113549.1.1.4')
+ RSA_SHA1 = algorithm_null_params('1.2.840.113549.1.1.5')
+ RSA_SHA224 = algorithm_null_params('1.2.840.113549.1.1.14')
+ RSA_SHA256 = algorithm_null_params('1.2.840.113549.1.1.11')
+ RSA_SHA384 = algorithm_null_params('1.2.840.113549.1.1.12')
+ RSA_SHA512 = algorithm_null_params('1.2.840.113549.1.1.13')
+ end
+
+ end
+end
+
View
257 lib/ruby/shared/krypt/asn1/template.rb
@@ -0,0 +1,257 @@
+module Krypt::ASN1
+ module Template
+ include Comparable
+
+ module Sequence
+ include Template
+ def self.included(base)
+ Template.init_cons_definition(base) do
+ :SEQUENCE
+ end
+ end
+ end
+
+ module Set
+ include Template
+ def self.included(base)
+ Template.init_cons_definition(base) do
+ :SET
+ end
+ end
+ end
+
+ module Choice
+ include Template
+
+ def self.included(base)
+ Template._mod_included_callback(base)
+ definition = {
+ codec: :CHOICE,
+ layout: []
+ }
+ base.instance_variable_set(:@definition, definition)
+ base.extend Template::ChoiceAccessor
+ base.extend Template::ChoiceDefinitions
+ base.extend Template::Parser
+ base.asn1_attr_accessor :value, :@value
+ base.asn1_attr_accessor :tag, :@tag
+ base.asn1_attr_accessor :type, :@type
+ end
+ end
+
+ module SequenceOf
+ include Template
+ def self.included(base)
+ Template.init_cons_of_definition(base) do
+ :SEQUENCE_OF
+ end
+ end
+ end
+
+ module SetOf
+ include Template
+ def self.included(base)
+ Template.init_cons_of_definition(base) do
+ :SET_OF
+ end
+ end
+ end
+
+ private
+
+ def self.init_cons_definition(base)
+ _mod_included_callback(base)
+ definition = {
+ codec: yield,
+ layout: [],
+ min_size: 0
+ }
+ base.instance_variable_set(:@definition, definition)
+ base.extend Template::Accessor
+ base.extend Template::ConstructedDefinitions
+ base.extend Template::Parser
+ end
+
+ def self.init_cons_of_definition(base)
+ _mod_included_callback(base)
+ definition = { codec: yield }
+ base.instance_variable_set(:@definition, definition)
+ base.extend Template::Accessor
+ base.extend Template::ConstructedOfDefinitions
+ base.extend Template::Parser
+ base.asn1_attr_accessor :value, :@value
+ end
+
+ module GeneralDefinitions
+ def init_methods
+ declare_prim(:asn1_boolean, Krypt::ASN1::BOOLEAN)
+ declare_prim(:asn1_integer, Krypt::ASN1::INTEGER)
+ declare_prim(:asn1_bit_string, Krypt::ASN1::BIT_STRING)
+ declare_prim(:asn1_octet_string, Krypt::ASN1::OCTET_STRING)
+ declare_prim(:asn1_null, Krypt::ASN1::NULL)
+ declare_prim(:asn1_object_id, Krypt::ASN1::OBJECT_ID)
+ declare_prim(:asn1_enumerated, Krypt::ASN1::ENUMERATED)
+ declare_prim(:asn1_utf8_string, Krypt::ASN1::UTF8_STRING)
+ declare_prim(:asn1_numeric_string, Krypt::ASN1::NUMERIC_STRING)
+ declare_prim(:asn1_printable_string, Krypt::ASN1::PRINTABLE_STRING)
+ declare_prim(:asn1_t61_string, Krypt::ASN1::T61_STRING)
+ declare_prim(:asn1_videotex_string, Krypt::ASN1::VIDEOTEX_STRING)
+ declare_prim(:asn1_ia5_string, Krypt::ASN1::IA5_STRING)
+ declare_prim(:asn1_utc_time, Krypt::ASN1::UTC_TIME)
+ declare_prim(:asn1_generalized_time, Krypt::ASN1::GENERALIZED_TIME)
+ declare_prim(:asn1_graphic_string, Krypt::ASN1::GRAPHIC_STRING)
+ declare_prim(:asn1_iso64_string, Krypt::ASN1::ISO64_STRING)
+ declare_prim(:asn1_general_string, Krypt::ASN1::GENERAL_STRING)
+ declare_prim(:asn1_universal_string, Krypt::ASN1::UNIVERSAL_STRING)
+ declare_prim(:asn1_bmp_string, Krypt::ASN1::BMP_STRING)
+
+ declare_special_typed(:asn1_template, :TEMPLATE)
+ declare_special_typed(:asn1_sequence_of, :SEQUENCE_OF)
+ declare_special_typed(:asn1_set_of, :SET_OF)
+
+ declare_any
+ end
+
+ def self.add_to_definition(klass, deff)
+ cur_def = klass.instance_variable_get(:@definition)
+ cur_def[:layout] << deff
+ codec = cur_def[:codec]
+ if codec == :SEQUENCE || codec == :SET
+ increase_min_size(cur_def, deff[:options])
+ end
+ end
+
+ private
+
+ def self.increase_min_size(cur_def, cur_opts)
+ cur_opts ||= {}
+ default = cur_opts[:default]
+ optional = cur_opts[:optional]
+ unless optional || default != nil
+ cur_def[:min_size] += 1
+ end
+ end
+ end
+
+ module Accessor
+ def asn1_attr_accessor(name, iv_name)
+ define_method name do
+ _get_callback(iv_name)
+ end
+ define_method "#{name.to_s}=".to_sym do |value|
+ _set_callback(iv_name, value)
+ end
+ end
+ end
+
+ module ChoiceAccessor
+ def asn1_attr_accessor(name, iv_name)
+ define_method name do
+ _get_callback_choice(iv_name)
+ end
+ define_method "#{name.to_s}=".to_sym do |value|
+ _set_callback_choice(iv_name, value)
+ end
+ end
+ end
+
+ module ChoiceDefinitions
+ extend GeneralDefinitions
+ class << self
+ define_method :declare_prim do |meth, type|
+ define_method meth do |opts=nil|
+ GeneralDefinitions.add_to_definition(self, {
+ codec: :PRIMITIVE,
+ type: type,
+ options: opts
+ })
+ end
+ end
+
+ define_method :declare_special_typed do |meth, codec|
+ define_method meth do |type, opts=nil|
+ raise ArgumentError.new "Type must not be nil" if type == nil
+ GeneralDefinitions.add_to_definition(self, {
+ codec: codec,
+ type: type,
+ options: opts
+ })
+ end
+ end
+
+ define_method :declare_any do
+ define_method :asn1_any do |opts=nil|
+ GeneralDefinitions.add_to_definition(self, {
+ codec: :ANY,
+ type: Krypt::ASN1::ASN1Data,
+ options: opts
+ })
+ end
+ end
+ end
+
+ init_methods
+ end
+
+ module ConstructedDefinitions
+ extend GeneralDefinitions
+ class << self
+ define_method :declare_prim do |meth, type|
+ define_method meth do |name, opts=nil|
+ raise ArgumentError.new "Name must not be nil" if name == nil
+ iv_name = ('@' + name.to_s).to_sym
+ asn1_attr_accessor name, iv_name
+
+ GeneralDefinitions.add_to_definition(self, {
+ codec: :PRIMITIVE,
+ type: type,
+ name: iv_name,
+ options: opts
+ })
+ end
+ end
+
+ define_method :declare_special_typed do |meth, codec|
+ define_method meth do |name, type, opts=nil|
+ raise ArgumentError.new "Name must not be nil" if name == nil
+ raise ArgumentError.new "Type must not be nil" if type == nil
+ iv_name = ('@' + name.to_s).to_sym
+ asn1_attr_accessor name, iv_name
+
+ GeneralDefinitions.add_to_definition(self, {
+ codec: codec,
+ type: type,
+ name: iv_name,
+ options: opts
+ })
+ end
+ end
+
+ define_method :declare_any do
+ define_method :asn1_any do |name, opts=nil|
+ raise ArgumentError.new "Name must not be nil" if name == nil
+ iv_name = ('@' + name.to_s).to_sym
+ asn1_attr_accessor name, iv_name
+
+ GeneralDefinitions.add_to_definition(self, {
+ codec: :ANY,
+ type: Krypt::ASN1::ASN1Data,
+ name: iv_name,
+ options: opts
+ })
+ end
+ end
+ end
+
+ init_methods
+ end
+
+ module ConstructedOfDefinitions
+ def asn1_type(type)
+ raise ArgumentError.new "Type must not be nil" if type == nil
+ cur_def = instance_variable_get(:@definition)
+ cur_def[:type] = type
+ end
+ end
+ end
+end
View
57 lib/ruby/shared/krypt/codec.rb
@@ -0,0 +1,57 @@
+module Krypt
+
+ # Abstract class that represents filters that can be combined with ordinary
+ # IO instances, filtering the output before reading/writing to the underlying
+ # IO. IOFilter instances can be stacked on top of each other, forming a
+ # "filter chain" that "peels of" multiple layers of encoding for example.
+ #
+ # IOFilter supports a basic IO interface that responds to IO#read, IO#write
+ # and IO#close.
+ #
+ # When reading from the IOFilter, the data will first be read from the IO,
+ # processed according to the rules of the filter and only then passed on.
+ #
+ # When writing to the IOFilter, the data will first be processed by
+ # applying the filter and only then written to the IO instance.
+ #
+ # Closing the IOFilter with IOFilter#close guarantees (among possibly
+ # additional things) a call to IO#close on the underlying IO.
+ class IOFilter
+
+ #
+ # call-seq:
+ # IOFilter.new(io) [{ |filter| block }] -> IOFilter
+ #
+ # Constructs a new IOFilter with +io+ as its underlying IO.
+ # Takes an optional block which is yielded the IOFilter +filter+.
+ # After execution of the block, it is guaranteed that IOFilter#close
+ # gets called on the IOFilter.
+ #
+ def initialize(io)
+ @io = io
+ if block_given?
+ begin
+ yield self
+ ensure
+ close
+ end
+ end
+ end
+
+ #
+ # call-seq:
+ # io.close -> nil
+ #
+ # Calls, among possibly additional cleanup, IO#close on the underlying
+ # IO.
+ def close
+ @io.close
+ end
+ end
+
+
+end
+
+require_relative 'codec/hex'
+require_relative 'codec/base64'
+
View
140 lib/ruby/shared/krypt/codec/base64.rb
@@ -0,0 +1,140 @@
+require_relative 'base_codec'
+
+module Krypt::Base64
+
+ module Base64Impl #:nodoc:
+ include Krypt::BaseCodec
+
+ def compute_len(len, a, b)
+ len -= @buf.size if @buf
+ ret = a * len / b
+ remainder = ret % a
+ if remainder
+ ret += a - remainder
+ end
+ ret
+ end
+
+ def compute_encode_read_len(len)
+ compute_len(len, 3, 4)
+ end
+
+ def compute_decode_read_len(len)
+ compute_len(len, 4, 3)
+ end
+
+ def generic_close
+ if @write
+ @io.write(Krypt::Base64.encode(@buf)) if @buf
+ else
+ raise Krypt::Base64::Base64Error.new("Remaining bytes in buffer") if @buf
+ end
+ end
+ end
+
+ private_constant :Base64Impl
+
+ # Base64-encodes any data written or read from it in the process.
+ #
+ # === Example: Base64-encode data and write it to a file
+ #
+ # f = File.open("b64", "wb")
+ # b64 = Krypt::Base64::Encoder.new(f)
+ # b64 << "one"
+ # b64 << "two"
+ # b64.close # => contents in file will be encoded
+ #
+ # === Example: Reading from a file and Base64-encoding the data
+ #
+ # f = File.open("document", "rb")
+ # b64 = Krypt::Base64::Encoder.new(f)
+ # b64data = b64.read # => result is encoded
+ # b64.close
+ #
+ class Encoder < Krypt::IOFilter
+ include Base64Impl
+
+ #
+ # call-seq:
+ # in.read([len=nil]) -> String or nil
+ #
+ # Reads from the underlying IO and Base64-encodes the data.
+ # Please see IO#read for details. Note that in-place reading into
+ # a buffer is not supported.
+ #
+ def read(len=nil)
+ read_len = len ? compute_encode_read_len(len) : nil
+ generic_read(len, read_len) { |data| Krypt::Base64.encode(data) }
+ end
+
+ #
+ # call-seq:
+ # out.write(string) -> Integer
+ #
+ # Base64-encodes +string+ and writes it to the underlying IO.
+ # Please see IO#write for further details.
+ #
+ def write(data)
+ generic_write(data, 3) { |data| Krypt::Base64.encode(data) }
+ end
+ alias << write
+
+ def close
+ generic_close
+ super
+ end
+
+ end
+
+ # Base64-decodes any data written or read from it in the process.
+ #
+ # === Example: Reading and decoding Base64-encoded data from a file
+ #
+ # f = File.open("b64", "rb")
+ # b64 = Krypt::Base64::Decoder.new(f)
+ # plain = b64.read # => result is decoded
+ # b64.close
+ #
+ # === Example: Writing to a file while Base64-decoding the data
+ #
+ # f = File.open("document", "wb")
+ # b64 = Krypt::Base64::Decoder.new(f)
+ # b64data = ... #some Base64-encoded data
+ # b64 << b64data
+ # b64.close # => contents in file will be decoded
+ #
+ class Decoder < Krypt::IOFilter
+ include Base64Impl
+
+ #
+ # call-seq:
+ # in.read([len=nil]) -> String or nil
+ #
+ # Reads from the underlying IO and Base64-decodes the data.
+ # Please see IO#read for further details. Note that in-place reading into
+ # a buffer is not supported.
+ #
+ def read(len=nil)
+ read_len = len ? compute_decode_read_len(len) : nil
+ generic_read(len, read_len) { |data| Krypt::Base64.decode(data) }
+ end
+
+ #
+ # call-seq:
+ # out.write(string) -> Integer
+ #
+ # Base64-decodes string and writes it to the underlying IO.
+ # Please see IO#write for further details.
+ #
+ def write(data)
+ generic_write(data, 4) { |data| Krypt::Base64.decode(data) }
+ end
+ alias << write
+
+ def close
+ generic_close
+ super
+ end
+ end
+
+end
View
36 lib/ruby/shared/krypt/codec/base_codec.rb
@@ -0,0 +1,36 @@
+module Krypt::BaseCodec #:nodoc:
+
+ def generic_read(len, read_len)
+ data = @io.read(read_len)
+ data = yield data if data
+ if @buf
+ data = data || ""
+ data = @buf << data
+ end
+ return data unless len && data
+ dlen = data.size
+ remainder = dlen - len
+ update_buffer(data, dlen, remainder)
+ data
+ end
+
+ def generic_write(data, blk_size)
+ return 0 unless data
+ @write = true
+ data = @buf ? @buf << data : data.dup
+ dlen = data.size
+ remainder = dlen % blk_size
+ update_buffer(data, dlen, remainder)
+ @io.write(yield data) if data.size > 0
+ end
+
+ def update_buffer(data, dlen, remainder)
+ if remainder > 0
+ @buf = data.slice!(dlen - remainder, remainder)
+ else
+ @buf = nil
+ end
+ end
+
+end
+
View
122 lib/ruby/shared/krypt/codec/hex.rb
@@ -0,0 +1,122 @@
+require_relative 'base_codec'
+
+module Krypt::Hex
+
+ module HexImpl #:nodoc:
+ include Krypt::BaseCodec
+
+ def compute_encode_read_len(len)
+ len
+ end
+
+ def compute_decode_read_len(len)
+ len * 2
+ end
+
+ def generic_close
+ raise Krypt::Hex::HexError.new("Remaining bytes in buffer") if @buf
+ end
+ end
+
+ private_constant :HexImpl
+
+
+ # Hex-encodes any data written or read from it in the process.
+ #
+ # === Example: Hex-encode data and write it to a file
+ #
+ # f = File.open("hex", "wb")
+ # hex = Krypt::Hex::Encoder.new(f)
+ # hex << "one"
+ # hex << "two"
+ # hex.close # => contents in file will be encoded
+ #
+ # === Example: Reading from a file and hex-encoding the data
+ #
+ # f = File.open("document", "rb")
+ # hex = Krypt::Hex::Encoder.new(f)
+ # hexdata = hex.read # => result is encoded
+ # hex.close
+ #
+ class Encoder < Krypt::IOFilter
+ include HexImpl
+
+ #
+ # call-seq:
+ # in.read([len=nil]) -> String or nil
+ #
+ # Reads from the underlying IO and hex-encodes the data.
+ # Please see IO#read for details. Note that in-place reading into
+ # a buffer is not supported.
+ #
+ def read(len=nil)
+ read_len = len ? compute_encode_read_len(len) : nil
+ generic_read(len, read_len) { |data| Krypt::Hex.encode(data) }
+ end
+
+ #
+ # call-seq:
+ # out.write(string) -> Integer
+ #
+ # Hex-encodes +string+ and writes it to the underlying IO.
+ # Please see IO#write for further details.
+ #
+ def write(data)
+ generic_write(data, 1) { |data| Krypt::Hex.encode(data) }
+ end
+ alias << write
+
+ end
+
+ # Hex-decodes any data written or read from it in the process.
+ #
+ # === Example: Reading and decoding hex-encoded data from a file
+ #
+ # f = File.open("hex", "rb")
+ # hex = Krypt::Hex::Decoder.new(f)
+ # plain = hex.read # => result is decoded
+ # hex.close
+ #
+ # === Example: Writing to a file while hex-decoding the data
+ #
+ # f = File.open("document", "wb")
+ # hex = Krypt::Hex::Decoder.new(f)
+ # hexdata = ... #some hex-encoded data
+ # hex << hexdata
+ # hex.close # => contents in file will be decoded
+ #
+ class Decoder < Krypt::IOFilter
+ include HexImpl
+
+ #
+ # call-seq:
+ # in.read([len=nil], [buf=nil]) -> String or nil
+ #
+ # Reads from the underlying IO and hex-decodes the data.
+ # Please see IO#read for further details. Note that in-place reading into
+ # a buffer is not supported.
+ #
+ def read(len=nil)
+ read_len = len ? compute_decode_read_len(len) : nil
+ generic_read(len, read_len) { |data| Krypt::Hex.decode(data) }
+ end
+
+ #
+ # call-seq:
+ # out.write(string) -> Integer
+ #
+ # Hex-decodes string and writes it to the underlying IO.
+ # Please see IO#write for further details.
+ #
+ def write(data)
+ generic_write(data, 2) { |data| Krypt::Hex.decode(data) }
+ end
+ alias << write
+
+ def close
+ generic_close
+ super
+ end
+
+ end
+end
View
8 lib/ruby/shared/krypt/core/version.rb
@@ -0,0 +1,8 @@
+module Krypt
+ module Core
+ class Version
+ VERSION = "0.1.0.dev"
+ end
+ end
+end
+
View
112 lib/ruby/shared/krypt/digest.rb
@@ -0,0 +1,112 @@
+##
+# Digest allows you to compute message digests (sometimes
+# interchangeably called "hashes") of arbitrary data that are
+# cryptographically secure, i.e. a Digest implements a secure one-way
+# function.
+#
+# One-way functions offer some useful properties. E.g. given two
+# distinct inputs the probability that both yield the same output
+# is highly unlikely. Combined with the fact that every message digest
+# algorithm has a fixed-length output of just a few bytes, digests are
+# often used to create unique identifiers for arbitrary data. A common
+# example is the creation of a unique id for binary documents that are
+# stored in a database.
+#
+# Another useful characteristic of one-way functions (and thus the name)
+# is that given a digest there is no indication about the original
+# data that produced it, i.e. the only way to identify the original input
+# is to "brute-force" through every possible combination of inputs.
+#
+# These characteristics make one-way functions also ideal companions
+# for public key signature algorithms: instead of signing an entire
+# document, first a hash of the document is produced with a considerably
+# faster message digest algorithm and only the few bytes of its output
+# need to be signed using the slower public key algorithm. To validate
+# the integrity of a signed document, it suffices to re-compute the hash
+# and verify that it is equal to that in the signature.
+#
+# Among the supported message digest algorithms are:
+# * SHA1, SHA224, SHA256, SHA384 and SHA512
+# * MD5
+# * RIPEMD160
+#
+# For each of these algorithms, there is a convenient way to create
+# instances of Digest using them, for example
+#
+# digest = Krypt::Digest::SHA1.new
+#
+# === Creating Digest by name or by Object Identifier
+#
+# Each supported digest algorithm has an Object Identifier (OID) associated
+# with it. A Digest can either be created by passing the string
+# representation of the corresponding object identifier or by a string
+# representation of the algorithm name.
+#
+# For example, the OBJECT IDENTIFIER for SHA-1 is 1.3.14.3.2.26, so it can
+# be instantiated like this:
+#
+# d = Krypt::Digest.new("1.3.14.3.2.26")
+# d = Krypt::Digest.new("SHA1")
+# d = Krypt::Digest.new("sha1")
+#
+# Algorithm names may either be all upper- or all lowercase, hyphens are
+# generally stripped: for instance SHA-1 becomes "SHA1", RIPEMD-160
+# becomes "RIPEMD160".
+#
+# "Breaking" a message digest algorithm means defying its one-way
+# function characteristics, i.e. producing a collision or finding a way
+# to get to the original data by means that are more efficient than
+# brute-forcing etc. Older digest algorithms can be considered broken
+# in this sense, even the very popular MD5 and SHA1 algorithms. Should
+# security be your highest concern, then you should probably rely on
+# SHA224, SHA256, SHA384 or SHA512.
+#
+# === Hashing a file
+#
+# data = File.read('document')
+# sha256 = Krypt::Digest::SHA256.new
+# digest = sha256.digest(data)
+#
+# === Hashing several pieces of data at once
+#
+# data1 = File.read('file1')
+# data2 = File.read('file2')
+# data3 = File.read('file3')
+# sha256 = Krypt::Digest::SHA256.new
+# sha256 << data1
+# sha256 << data2
+# sha256 << data3
+# digest = sha256.digest
+#
+# === Reuse a Digest instance
+#
+# data1 = File.read('file1')
+# sha256 = Krypt::Digest::SHA256.new
+# digest1 = sha256.digest(data1)
+#
+# data2 = File.read('file2')
+# sha256.reset
+# digest2 = sha256.digest(data2)
+#
+module Krypt::Digest
+
+ ##
+ # Raised whenever a problem with digests occurs.
+ #
+ class DigestError < Krypt::Error; end
+
+ def self.new(name_or_oid, provider=nil)
+ receiver = provider ? provider : Krypt::Provider
+ f = ->(_) { new_service(Krypt::Digest, name_or_oid) }
+ receiver.instance_eval(&f)
+ end
+
+ %w(SHA1 SHA224 SHA256 SHA384 SHA512 RIPEMD160 MD5).each do |alg|
+ mod = Module.new do
+ define_singleton_method(:new) { Krypt::Digest.new(alg) }
+ end
+ const_set(alg, mod)
+ end
+
+end
+
View
69 lib/ruby/shared/krypt/hmac.rb
@@ -0,0 +1,69 @@
+module Krypt
+ class HMAC
+ include Krypt::Helper::XOR
+
+ def initialize(digest, key)
+ @digest = digest
+ @key = process_key(key)
+
+ # hash ipad
+ hash_pad(0x36)
+ end
+
+ def update(data)
+ @digest << data
+ end
+ alias << update
+
+ def digest
+ inner_digest = @digest.digest
+ # hash opad
+ hash_pad(0x5c)
+ @digest << inner_digest
+ @digest.digest
+ end
+
+ def hexdigest
+ Krypt::Hex.encode(digest)
+ end
+
+ class << self
+
+ def digest(md, key, data)
+ hmac = self.new(md, key)
+ hmac << data
+ hmac.digest
+ end
+
+ def hexdigest(md, key, data)
+ Krypt::Hex.encode(digest(md, key, data))
+ end
+
+ end
+
+ private
+
+ def process_key(key)
+ block_len = @digest.block_length
+
+ if key.size > block_len
+ key = @digest.digest(key)
+ end
+
+ if key.size < block_len
+ new_key = key.dup.tap do |new_key|
+ (block_len - key.size).times { new_key << 0 }
+ end
+ else
+ key
+ end
+ end
+
+ def hash_pad(pad_char)
+ @digest << String.new.tap do |s|
+ @key.each_byte { |b| s << (pad_char ^ b) }
+ end
+ end
+
+ end
+end
View
38 lib/ruby/shared/krypt/ossl.rb
@@ -0,0 +1,38 @@
+=begin
+
+= Info
+
+krypt-ossl - A krypt shim to offer the same API as the Ruby OpenSSL extension
+
+Copyright (C) 2013
+Martin Bosslet <martin.bosslet@gmail.com>
+All rights reserved.
+
+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.
+
+=end
+
+require 'krypt'
+
+module OpenSSL
+ class Error < StandardError; end
+end unless defined? OpenSSL
+
+require_relative 'ossl/pkcs5'
View
17 lib/ruby/shared/krypt/ossl/pkcs5.rb
@@ -0,0 +1,17 @@
+module OpenSSL
+
+ #
+ # Offers the same functionality as OpenSSL::PKCS5
+ #
+ module PKCS5
+ module_function
+
+ def pbkdf2_hmac_sha1(pass, salt, iter, keylen)
+ Krypt::PBKDF2.new(Krypt::Digest::SHA1.new).generate(pass, salt, iter, keylen)
+ end
+
+ def pbkdf2_hmac(pass, salt, iter, keylen, digest)
+ Krypt::PBKDF2.new(digest).generate(pass, salt, iter, keylen)
+ end
+ end unless defined? OpenSSL::PKCS5
+end
View
1 lib/ruby/shared/krypt/pkcs5.rb
@@ -0,0 +1 @@
+require_relative 'pkcs5/pbkdf2'
View
41 lib/ruby/shared/krypt/pkcs5/pbkdf2.rb
@@ -0,0 +1,41 @@
+module Krypt
+ class PBKDF2
+ include Krypt::Helper::XOR
+
+ MAX_FACTOR = (2 ** 32) - 1
+
+ def initialize(digest)
+ @digest = digest
+ @block_size = digest.digest_length
+ end
+
+ def generate(pwd, salt, iter, outlen)
+ raise "outlen too large" if outlen > MAX_FACTOR * @block_size
+
+ @digest.reset
+ num_blocks = (outlen.to_f / @block_size).ceil
+ # enforces ASCII-8BIT
+ String.new.tap do |result|
+ 1.upto(num_blocks) { |i| result << f(pwd, salt, iter, i) }
+ end.slice(0, outlen)
+ end
+
+ def generate_hex(pwd, salt, iter, outlen)
+ Krypt::Hex.encode(generate(pwd, salt, iter, outlen))
+ end
+
+ private
+
+ def f(pwd, salt, iter, i)
+ u = salt + [i].pack("L>")
+ ("\0" * @block_size).force_encoding(Encoding::BINARY).tap do |result|
+ 1.upto(iter) do
+ u = Krypt::HMAC.digest(@digest, pwd, u)
+ xor!(result, u)
+ end
+ end
+ end
+
+ end
+end
+
View
35 lib/ruby/shared/krypt/provider.rb
@@ -0,0 +1,35 @@
+module Krypt::Provider
+
+ PROVIDERS = {}
+ PROVIDER_LIST = []
+
+ class AlreadyExistsError < Krypt::Error; end
+
+ class ServiceNotAvailableError < Krypt::Error; end
+
+ module_function
+
+ def register(name, provider)
+ raise AlreadyExistsError.new("There already is a Provider named #{name}") if PROVIDERS.has_key?(name)
+ PROVIDERS[name] = provider
+ PROVIDER_LIST << name
+ end
+
+ def by_name(name)
+ PROVIDERS[name]
+ end
+
+ def remove(name)
+ PROVIDERS.delete(name)
+ PROVIDER_LIST.delete(name)
+ end
+
+ def new_service(klass, *args)
+ PROVIDER_LIST.reverse.each do |name|
+ service = PROVIDERS[name].new_service(klass, *args)
+ return service if service
+ end
+ raise ServiceNotAvailableError.new("The requested service is not available")
+ end
+
+end
View
3 lib/ruby/shared/krypt/x509.rb
@@ -0,0 +1,3 @@
+require_relative 'x509/common'
+require_relative 'x509/certificate'
+require_relative 'x509/crl'
View
36 lib/ruby/shared/krypt/x509/certificate.rb
@@ -0,0 +1,36 @@
+module Krypt
+ module X509
+
+ class Certificate
+ include ASN1::Template::Sequence
+
+ class SubjectPublicKeyInfo
+ include ASN1::Template::Sequence
+
+ asn1_template :algorithm, ASN1::AlgorithmIdentifier
+ asn1_bit_string :subject_pkey
+ end
+
+ class TBSCertificate
+ include ASN1::Template::Sequence
+
+ asn1_integer :version, tag: 0, tagging: :EXPLICIT, default: 0
+ asn1_integer :serial
+ asn1_template :algorithm, ASN1::AlgorithmIdentifier
+ asn1_template :issuer, ASN1::DistinguishedName
+ asn1_template :validity, X509::Validity
+ asn1_template :subject, ASN1::DistinguishedName
+ asn1_template :subject_pkey, SubjectPublicKeyInfo
+ asn1_bit_string :issuer_id, tag: 1, tagging: :IMPLICIT, optional: true
+ asn1_bit_string :subject_id, tag: 2, tagging: :IMPLICIT, optional: true
+ asn1_sequence_of :extensions, X509::Extension, tag: 3, tagging: :EXPLICIT, optional: true
+ end
+
+ asn1_template :tbs_cert, TBSCertificate
+ asn1_template :algorithm, ASN1::AlgorithmIdentifier
+ asn1_bit_string :signature
+ end
+
+ end
+end
+
View
41 lib/ruby/shared/krypt/x509/common.rb
@@ -0,0 +1,41 @@
+module Krypt
+ module X509
+
+ class Extension
+ include ASN1::Template::Sequence
+
+ asn1_object_id :id
+ asn1_boolean :critical, default: false
+ asn1_octet_string :value
+ end
+
+ class Attribute
+ include ASN1::Template::Sequence
+
+ asn1_object_id :type
+ asn1_set_of :value, ASN1::ASN1Data
+ end
+
+ class IssuerSerialNumber
+ include Krypt::ASN1::Template::Sequence
+
+ asn1_template :issuer, ASN1::DistinguishedName
+ asn1_integer :serial
+ end
+
+ class Time
+ include ASN1::Template::Choice
+
+ asn1_utc_time
+ asn1_generalized_time
+ end
+
+ class Validity
+ include ASN1::Template::Sequence
+
+ asn1_template :not_before, X509::Time
+ asn1_template :not_after, X509::Time
+ end
+
+ end
+end
View
33 lib/ruby/shared/krypt/x509/crl.rb
@@ -0,0 +1,33 @@
+module Krypt
+ module X509
+
+ class CRL
+ include ASN1::Template::Sequence
+
+ class RevokedCertificates
+ include ASN1::Template::Sequence
+
+ asn1_integer :serial_number
+ asn1_template :revocation_date, X509::Time
+ asn1_template :crl_entry_extensions, X509::Extension
+ end
+
+ class TBSCertList
+ include ASN1::Template::Sequence
+
+ asn1_integer :version, default: 1
+ asn1_template :signature_algorithm, ASN1::AlgorithmIdentifier
+ asn1_template :issuer, ASN1::DistinguishedName
+ asn1_template :this_update, X509::Time
+ asn1_template :next_update, X509::Time
+ asn1_sequence_of :revoked_certificates, RevokedCertificates, optional: true
+ asn1_template :extensions, X509::Extension, tag: 0, tagging: :EXPLICIT, optional: true
+ end
+
+ asn1_template :tbs_cert_list, TBSCertList
+ asn1_template :signature_algorithm, ASN1::AlgorithmIdentifier
+ asn1_bit_string :signature
+ end
+
+ end
+end
View
32 lib/ruby/shared/krypt_missing.rb
@@ -0,0 +1,32 @@
+unless Kernel.respond_to? :private_constant
+ module Kernel
+ def private_constant(*)
+ # TODO delete when sufficiently supported
+ nil
+ end
+ end
+end
+
+module Krypt
+ module Helper
+
+ module XOR
+ def xor(s1, s2)
+ String.new.tap do |result|
+ s1.bytes.each_with_index do |b, i|
+ result << (b ^ s2.getbyte(i))
+ end
+ end
+ end
+
+ def xor!(recv, other)
+ recv.bytes.each_with_index do |b, i|
+ recv.setbyte(i, b ^ other.getbyte(i))
+ end
+ recv
+ end
+ end
+
+ end
+end
+
View
BIN lib/ruby/shared/kryptcore.jar
Binary file not shown.
View
BIN lib/ruby/shared/kryptproviderjdk.jar
Binary file not shown.
View
1 lib/ruby/shared/openssl.rb
@@ -30,4 +30,5 @@
require 'openssl/ssl-internal'
require 'openssl/x509-internal'
require 'openssl/pkcs12'
+ require 'krypt/ossl'
end

0 comments on commit cc9acba

Please sign in to comment.
Something went wrong with that request. Please try again.