block_cipher_kit 0.0.2 → 0.0.3
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 +4 -4
- data/block_cipher_kit.gemspec +5 -0
- data/lib/block_cipher_kit/aes_256_cbc_scheme.rb +1 -1
- data/lib/block_cipher_kit/aes_256_cfb_civ_scheme.rb +2 -2
- data/lib/block_cipher_kit/aes_256_cfb_scheme.rb +1 -1
- data/lib/block_cipher_kit/aes_256_ctr_scheme.rb +1 -1
- data/lib/block_cipher_kit/aes_256_gcm_scheme.rb +2 -2
- data/lib/block_cipher_kit/base_scheme.rb +26 -0
- data/lib/block_cipher_kit/version.rb +1 -1
- data/lib/block_cipher_kit.rb +0 -2
- data/rbi/block_cipher_kit.rbi +12 -16
- data/test/schemes_test.rb +20 -0
- metadata +5 -4
- data/lib/block_cipher_kit/key_material.rb +0 -17
- data/test/key_material_test.rb +0 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 20609183e16f9958a035b581945c5d891851a85df83cbd19741b3e94efe3a676
|
4
|
+
data.tar.gz: bee694246cdd3eae36af264e7fb3b90dc3179c22203f82e38d028a3733ee99a5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ac9365aa614c6b9f88fdad333da7577f6b2e1080430df7bafdbb15aba14f031183269407423e6ba79ba6757d9851f141bc09af7c82ed692830f95a7ca9d3ea48
|
7
|
+
data.tar.gz: 5620bce257285e2c18be847ce3557cc5876136562b4c5f619c6eda9c7d761de884dee493f218ae781879af17e7dd94ab7aa6fe7d1f58e884453ac1da1ab07673
|
data/block_cipher_kit.gemspec
CHANGED
@@ -10,7 +10,12 @@ Gem::Specification.new do |spec|
|
|
10
10
|
spec.license = "MIT"
|
11
11
|
spec.summary = "A thin toolkit for working with block cipher encryption."
|
12
12
|
spec.description = "A thin toolkit for working with block cipher encryption."
|
13
|
+
|
13
14
|
spec.homepage = "https://github.com/julik/block_cipher_kit"
|
15
|
+
# The homepage link on rubygems.org only appears if you add homepage_uri. Just spec.homepage is not enough.
|
16
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
17
|
+
spec.metadata["source_code_uri"] = spec.homepage
|
18
|
+
spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/CHANGELOG.md"
|
14
19
|
|
15
20
|
spec.required_ruby_version = ">= 2.7.0"
|
16
21
|
|
@@ -8,7 +8,7 @@ class BlockCipherKit::AES256CBCScheme < BlockCipherKit::BaseScheme
|
|
8
8
|
def initialize(encryption_key, iv_generator: SecureRandom)
|
9
9
|
raise ArgumentError, "#{required_encryption_key_length} bytes of key material needed, at the minimum" unless encryption_key.bytesize >= required_encryption_key_length
|
10
10
|
@iv_generator = iv_generator
|
11
|
-
@key =
|
11
|
+
@key = encryption_key.byteslice(0, 32)
|
12
12
|
end
|
13
13
|
|
14
14
|
def required_encryption_key_length
|
@@ -4,8 +4,8 @@ class BlockCipherKit::AES256CFBCIVScheme < BlockCipherKit::BaseScheme
|
|
4
4
|
# @param encryption_key[String] a String in binary encoding containing the IV concatenated with the key for the cipher
|
5
5
|
def initialize(encryption_key, **)
|
6
6
|
raise ArgumentError, "#{required_encryption_key_length} bytes of key material needed, at the minimum" unless encryption_key.bytesize >= required_encryption_key_length
|
7
|
-
@iv =
|
8
|
-
@key =
|
7
|
+
@iv = encryption_key.byteslice(0, 16)
|
8
|
+
@key = encryption_key.byteslice(16, 32)
|
9
9
|
end
|
10
10
|
|
11
11
|
def required_encryption_key_length
|
@@ -4,7 +4,7 @@ class BlockCipherKit::AES256CFBScheme < BlockCipherKit::BaseScheme
|
|
4
4
|
def initialize(encryption_key, iv_generator: SecureRandom)
|
5
5
|
raise ArgumentError, "#{required_encryption_key_length} bytes of key material needed, at the minimum" unless encryption_key.bytesize >= required_encryption_key_length
|
6
6
|
@iv_generator = iv_generator
|
7
|
-
@key =
|
7
|
+
@key = encryption_key.byteslice(0, 32)
|
8
8
|
end
|
9
9
|
|
10
10
|
def required_encryption_key_length
|
@@ -7,7 +7,7 @@ class BlockCipherKit::AES256CTRScheme < BlockCipherKit::BaseScheme
|
|
7
7
|
def initialize(encryption_key, iv_generator: SecureRandom)
|
8
8
|
raise ArgumentError, "#{required_encryption_key_length} bytes of key material needed, at the minimum" unless encryption_key.bytesize >= required_encryption_key_length
|
9
9
|
@iv_generator = iv_generator
|
10
|
-
@key =
|
10
|
+
@key = encryption_key.byteslice(0, 32)
|
11
11
|
end
|
12
12
|
|
13
13
|
def required_encryption_key_length
|
@@ -7,8 +7,8 @@ class BlockCipherKit::AES256GCMScheme < BlockCipherKit::BaseScheme
|
|
7
7
|
def initialize(encryption_key, iv_generator: SecureRandom, auth_data: "")
|
8
8
|
raise ArgumentError, "#{required_encryption_key_length} bytes of key material needed, at the minimum" unless encryption_key.bytesize >= required_encryption_key_length
|
9
9
|
@iv_generator = iv_generator
|
10
|
-
@auth_data =
|
11
|
-
@key =
|
10
|
+
@auth_data = auth_data.b
|
11
|
+
@key = encryption_key.byteslice(0, 32)
|
12
12
|
end
|
13
13
|
|
14
14
|
def required_encryption_key_length
|
@@ -64,8 +64,34 @@ class BlockCipherKit::BaseScheme
|
|
64
64
|
buf.string
|
65
65
|
end
|
66
66
|
|
67
|
+
def inspect
|
68
|
+
# A reimplementation of #inspect based largely on
|
69
|
+
# https://alchemists.io/articles/ruby_object_inspection
|
70
|
+
pattern = +""
|
71
|
+
values = []
|
72
|
+
|
73
|
+
instance_variables.each do |name|
|
74
|
+
pattern << "#{name}=%s "
|
75
|
+
ivar_value = instance_variable_get(name)
|
76
|
+
if ivar_value.is_a?(String) && key_material_instance_variable_names.include?(name)
|
77
|
+
values.push("[SENSITIVE(#{ivar_value.bytesize * 8} bits)]")
|
78
|
+
else
|
79
|
+
values.push(ivar_value.inspect)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
format "#<%s:%#018x #{pattern.strip}>", self.class, object_id << 1, *values
|
84
|
+
end
|
85
|
+
|
67
86
|
private
|
68
87
|
|
88
|
+
# The names of instance variables which contain key material and need to be masked in the
|
89
|
+
# output of BaseScheme#inspect. This prevents us from leaking the key, while allowing each
|
90
|
+
# subclass to define which ivars it considers sensitive.
|
91
|
+
def key_material_instance_variable_names
|
92
|
+
[:@key, :@iv]
|
93
|
+
end
|
94
|
+
|
69
95
|
def read_copy_stream_via_cipher(source_io:, cipher:, read_limit: nil, destination_io: nil, finalize_cipher: true, &block_accepting_byte_chunks)
|
70
96
|
writable = BlockCipherKit::BlockWritable.new(destination_io, &block_accepting_byte_chunks)
|
71
97
|
cipher_io = BlockCipherKit::CipherIO.new(writable, cipher)
|
data/lib/block_cipher_kit.rb
CHANGED
@@ -21,13 +21,11 @@ module BlockCipherKit
|
|
21
21
|
autoload :ReadWindowIO, __dir__ + "/block_cipher_kit/read_window_io.rb"
|
22
22
|
autoload :BlockWritable, __dir__ + "/block_cipher_kit/block_writable.rb"
|
23
23
|
autoload :CipherIO, __dir__ + "/block_cipher_kit/cipher_io.rb"
|
24
|
-
autoload :KeyMaterial, __dir__ + "/block_cipher_kit/key_material.rb"
|
25
24
|
|
26
25
|
# private_constant :WriteWindowIO
|
27
26
|
# private_constant :ReadWindowIO
|
28
27
|
# private_constant :BlockWritable
|
29
28
|
# private_constant :CipherIO
|
30
|
-
# private_constant :KeyMaterial
|
31
29
|
|
32
30
|
autoload :BaseScheme, __dir__ + "/block_cipher_kit/base_scheme.rb"
|
33
31
|
autoload :PassthruScheme, __dir__ + "/block_cipher_kit/passthru_scheme.rb"
|
data/rbi/block_cipher_kit.rbi
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# typed: strong
|
2
2
|
module BlockCipherKit
|
3
|
-
VERSION = T.let("0.0.
|
3
|
+
VERSION = T.let("0.0.3", T.untyped)
|
4
4
|
|
5
5
|
# Allows an OpenSSL::Cipher to be written through as if it were an IO. This
|
6
6
|
# allows the cipher to be passed to things like IO.copy_stream
|
@@ -75,6 +75,17 @@ module BlockCipherKit
|
|
75
75
|
sig { params(from_ciphertext_io: RandomReadIO, range: T::Range[T.untyped]).returns(String) }
|
76
76
|
def decrypt_range(from_ciphertext_io:, range:); end
|
77
77
|
|
78
|
+
# sord omit - no YARD return type given, using untyped
|
79
|
+
sig { returns(T.untyped) }
|
80
|
+
def inspect; end
|
81
|
+
|
82
|
+
# sord omit - no YARD return type given, using untyped
|
83
|
+
# The names of instance variables which contain key material and need to be masked in the
|
84
|
+
# output of BaseScheme#inspect. This prevents us from leaking the key, while allowing each
|
85
|
+
# subclass to define which ivars it considers sensitive.
|
86
|
+
sig { returns(T.untyped) }
|
87
|
+
def key_material_instance_variable_names; end
|
88
|
+
|
78
89
|
# sord omit - no YARD type given for "source_io:", using untyped
|
79
90
|
# sord omit - no YARD type given for "cipher:", using untyped
|
80
91
|
# sord omit - no YARD type given for "read_limit:", using untyped
|
@@ -110,21 +121,6 @@ module BlockCipherKit
|
|
110
121
|
def write_copy_stream_via_cipher(cipher:, destination_io:, source_io: nil, read_limit: nil, &block_accepting_writable_io); end
|
111
122
|
end
|
112
123
|
|
113
|
-
# Allows a string with key material (like IV and key)
|
114
|
-
# to be concealed when an object holding it gets printed or show via #inspect
|
115
|
-
# :nodoc:
|
116
|
-
class KeyMaterial
|
117
|
-
extend Forwardable
|
118
|
-
|
119
|
-
# sord omit - no YARD type given for "str", using untyped
|
120
|
-
sig { params(str: T.untyped).void }
|
121
|
-
def initialize(str); end
|
122
|
-
|
123
|
-
# sord omit - no YARD return type given, using untyped
|
124
|
-
sig { returns(T.untyped) }
|
125
|
-
def inspect; end
|
126
|
-
end
|
127
|
-
|
128
124
|
# :nodoc:
|
129
125
|
# An adapter which allows a block that accepts chunks of
|
130
126
|
# written data to be used as an IO and passed to IO.copy_stream
|
data/test/schemes_test.rb
CHANGED
@@ -25,6 +25,12 @@ class SchemesTest < Minitest::Test
|
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
|
+
SCHEME_NAMES_INCLUDING_PASSTHRU.each do |scheme_class_name|
|
29
|
+
define_method "test_scheme #{scheme_class_name} encrypts and decrypts an empty message" do
|
30
|
+
assert_encrypts_and_decrypts_empty_message(scheme_class_name)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
28
34
|
SCHEME_NAMES_INCLUDING_PASSTHRU.each do |scheme_class_name|
|
29
35
|
define_method "test_scheme #{scheme_class_name} allows random access reads" do
|
30
36
|
assert_allows_random_access(scheme_class_name)
|
@@ -73,6 +79,20 @@ class SchemesTest < Minitest::Test
|
|
73
79
|
assert_equal ciphertexts.length, ciphertexts.uniq.length
|
74
80
|
end
|
75
81
|
|
82
|
+
def assert_encrypts_and_decrypts_empty_message(scheme_class_name)
|
83
|
+
rng = Random.new(Minitest.seed)
|
84
|
+
key = rng.bytes(48)
|
85
|
+
|
86
|
+
scheme = resolve(scheme_class_name).new(key)
|
87
|
+
ciphered_io = StringIO.new
|
88
|
+
scheme.streaming_encrypt(from_plaintext_io: StringIO.new, into_ciphertext_io: ciphered_io)
|
89
|
+
|
90
|
+
ciphered_io.rewind
|
91
|
+
decrypted = StringIO.new
|
92
|
+
scheme.streaming_decrypt(from_ciphertext_io: ciphered_io, into_plaintext_io: decrypted)
|
93
|
+
assert_equal 0, decrypted.size
|
94
|
+
end
|
95
|
+
|
76
96
|
def assert_encrypts_from_block_and_io(scheme_class_name)
|
77
97
|
rng = Random.new(Minitest.seed)
|
78
98
|
encryption_key = rng.bytes(64)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: block_cipher_kit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Julik Tarkhanov
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2025-02-
|
12
|
+
date: 2025-02-26 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: minitest
|
@@ -133,14 +133,12 @@ files:
|
|
133
133
|
- lib/block_cipher_kit/block_writable.rb
|
134
134
|
- lib/block_cipher_kit/cipher_io.rb
|
135
135
|
- lib/block_cipher_kit/io_types.rb
|
136
|
-
- lib/block_cipher_kit/key_material.rb
|
137
136
|
- lib/block_cipher_kit/passthru_scheme.rb
|
138
137
|
- lib/block_cipher_kit/read_window_io.rb
|
139
138
|
- lib/block_cipher_kit/version.rb
|
140
139
|
- lib/block_cipher_kit/write_window_io.rb
|
141
140
|
- rbi/block_cipher_kit.rbi
|
142
141
|
- test/cipher_io_test.rb
|
143
|
-
- test/key_material_test.rb
|
144
142
|
- test/known_ciphertexts/AES256CBCScheme.ciphertext.bin
|
145
143
|
- test/known_ciphertexts/AES256CFBCIVScheme.ciphertext.bin
|
146
144
|
- test/known_ciphertexts/AES256CFBScheme.ciphertext.bin
|
@@ -157,6 +155,9 @@ homepage: https://github.com/julik/block_cipher_kit
|
|
157
155
|
licenses:
|
158
156
|
- MIT
|
159
157
|
metadata:
|
158
|
+
homepage_uri: https://github.com/julik/block_cipher_kit
|
159
|
+
source_code_uri: https://github.com/julik/block_cipher_kit
|
160
|
+
changelog_uri: https://github.com/julik/block_cipher_kit/blob/main/CHANGELOG.md
|
160
161
|
allowed_push_host: https://rubygems.org
|
161
162
|
post_install_message:
|
162
163
|
rdoc_options: []
|
@@ -1,17 +0,0 @@
|
|
1
|
-
require "forwardable"
|
2
|
-
|
3
|
-
# Allows a string with key material (like IV and key)
|
4
|
-
# to be concealed when an object holding it gets printed or show via #inspect
|
5
|
-
# :nodoc:
|
6
|
-
class BlockCipherKit::KeyMaterial
|
7
|
-
extend Forwardable
|
8
|
-
def_delegators :@str, :b, :byteslice, :to_s, :to_str
|
9
|
-
|
10
|
-
def initialize(str)
|
11
|
-
@str = str
|
12
|
-
end
|
13
|
-
|
14
|
-
def inspect
|
15
|
-
"[SENSITIVE(#{@str.bytesize * 8} bits)]"
|
16
|
-
end
|
17
|
-
end
|
data/test/key_material_test.rb
DELETED
@@ -1,12 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative "test_helper"
|
4
|
-
|
5
|
-
class KeyMaterialTest < Minitest::Test
|
6
|
-
def test_conceals_but_provides_string_access
|
7
|
-
km = BlockCipherKit::KeyMaterial.new("foo")
|
8
|
-
assert_equal "[SENSITIVE(24 bits)]", km.inspect
|
9
|
-
assert_equal "foo", [km].join
|
10
|
-
assert_equal "foo".b, km.b
|
11
|
-
end
|
12
|
-
end
|