aesx 0.1.4 → 0.2.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.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/aesx.rb +32 -30
  3. metadata +3 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2ce5b5a60238ba024621270a96d2814f7907e647bc7f5a745dea8c7226ae56cc
4
- data.tar.gz: 167f9d6547c25e4d9f7b85b6444a60201d756121070bba228d244f65bd0d9c79
3
+ metadata.gz: 4df3e7ebfe10780119148530407dffbc8b4d76ff0e60665405a1096932f4d4f5
4
+ data.tar.gz: 8579a2f88160d2686bd8b94284986beba974e11a1ba6f2daeef9f755de5001c2
5
5
  SHA512:
6
- metadata.gz: 297d6f9efa3bf4ead66b6a70219e3cdf2bced2a40c406db6c653665fa74c28bd311faa47435fc595d9a17be7c377927d1c18e9ec6ef9e77190e6443b401cfafa
7
- data.tar.gz: d6242cb83ebe9d512fbeb1f621641fed8aea054057879750d1e50ab50a90b3acf6e73cbbed4dd2ad70b3520b8f0cf3c4d6471aef8f48d8a2dad90b57c09ede1b
6
+ metadata.gz: da63a66ca2fd099dd4473800f17cb2318a7b17fa17651a2ae8a9b438410d24c8255b63046bb1820f3de3ca82a0aecec53c90207a44995d2bbde5ac2d3944dfce
7
+ data.tar.gz: 980b512d63c2c4f36a33f926e542c449cfcc5f516c4eefa7a85e1bdc67113276f0ca3ef48e1027011621c7f66d74856deacd6fa0f2af1f237e89914aceaa95d2
data/lib/aesx.rb CHANGED
@@ -8,8 +8,8 @@ require_relative 'compression'
8
8
 
9
9
  # AESX - AES eXtended encryption library
10
10
  #
11
- # A lightweight encryption library that provides an extended version of
12
- # the popular AES gem interface with modern ciphers. The default cipher
11
+ # A lightweight encryption library that provides an extended version of
12
+ # the popular AES gem interface with modern ciphers. The default cipher
13
13
  # is AES-256-GCM.
14
14
  #
15
15
  # @example Basic usage
@@ -49,7 +49,7 @@ module AESX
49
49
  # @return [Array<String>] List of available cipher names
50
50
  def cipher_list
51
51
  openssl_ciphers = OpenSSL::Cipher.ciphers.map(&:upcase)
52
- CIPHER_SPECS.keys & openssl_ciphers
52
+ CIPHER_SPECS.keys & openssl_ciphers
53
53
  end
54
54
 
55
55
  # Encrypts plaintext using the specified key and options
@@ -97,7 +97,7 @@ module AESX
97
97
  def key(length = nil, format = :plain, cipher: 'AES-256-GCM')
98
98
  key_length = length ? length / 8 : CIPHER_SPECS[cipher.upcase][0]
99
99
  key = OpenSSL::Random.random_bytes(key_length)
100
- format == :base_64 ? Base64.encode64(key).chomp : key
100
+ format == :base_64 ? Base64.strict_encode64(key).chomp : key
101
101
  end
102
102
 
103
103
  # Generates a random initialization vector of appropriate length for the specified cipher
@@ -109,16 +109,16 @@ module AESX
109
109
  def iv(format = :plain, cipher: 'AES-256-GCM')
110
110
  iv_length = CIPHER_SPECS[cipher.upcase][1]
111
111
  iv = OpenSSL::Random.random_bytes(iv_length)
112
- format == :base_64 ? Base64.encode64(iv).chomp : iv
112
+ format == :base_64 ? Base64.strict_encode64(iv).chomp : iv
113
113
  end
114
-
114
+
115
115
  # Returns the default compression algorithm
116
116
  #
117
117
  # @return [Symbol, nil] The symbol representing the default algorithm, or nil if none available
118
118
  def default_compression
119
119
  AESCompression.default_algorithm
120
120
  end
121
-
121
+
122
122
  # Returns an array of available compression algorithms
123
123
  #
124
124
  # @return [Array<Symbol>] Symbols representing available compression algorithms
@@ -148,7 +148,7 @@ module AESX
148
148
  # allow laziness
149
149
  if opts.key?(:compress)
150
150
  opts[:compression] = opts.delete(:compress)
151
- end
151
+ end
152
152
  @options = {
153
153
  format: :base_64, # Default output format for encryption
154
154
  cipher: "AES-256-GCM", # GCM mode
@@ -198,7 +198,7 @@ module AESX
198
198
 
199
199
  # Get compression option from opts or fallback to options
200
200
  compression = opts.key?(:compression) ? opts[:compression] : @options[:compression]
201
-
201
+
202
202
  # If compression is a symbol or truthy value (but not true), use it as the algorithm
203
203
  if compression.is_a?(Symbol) || (compression && compression != true)
204
204
  # Check if specified algorithm is available
@@ -218,13 +218,13 @@ module AESX
218
218
  fmt = opts[:format] || @options[:format]
219
219
  case fmt
220
220
  when :base_64
221
- iv_b64 = Base64.encode64(iv).chomp
222
- ciphertext_b64 = Base64.encode64(ciphertext).chomp
223
- auth_tag_b64 = auth_tag ? Base64.encode64(auth_tag).chomp : nil
224
-
221
+ iv_b64 = Base64.strict_encode64(iv).chomp
222
+ ciphertext_b64 = Base64.strict_encode64(ciphertext).chomp
223
+ auth_tag_b64 = auth_tag ? Base64.strict_encode64(auth_tag).chomp : nil
224
+
225
225
  # Add compression flag
226
226
  comp_flag = compression_algorithm ? AESCompression::ALGORITHM_IDS[compression_algorithm].to_s : "0"
227
-
227
+
228
228
  if auth_tag_b64
229
229
  result = "#{iv_b64}$#{ciphertext_b64}$#{auth_tag_b64}$#{comp_flag}"
230
230
  else
@@ -236,10 +236,10 @@ module AESX
236
236
  # auth_tag length is 0-16, variable in CCM
237
237
  auth_tag_size = auth_tag ? auth_tag.bytesize : 0
238
238
  packed_lengths = ((iv.bytesize - 7) << 5) | (auth_tag_size & 0x1F)
239
-
239
+
240
240
  # Add a second byte for compression algorithm
241
241
  compression_byte = AESCompression::ALGORITHM_IDS[compression_algorithm] || 0
242
-
242
+
243
243
  if auth_tag
244
244
  pack_format = "CC a#{iv.bytesize} a* a#{auth_tag.bytesize}"
245
245
  [packed_lengths, compression_byte, iv, ciphertext, auth_tag].pack(pack_format)
@@ -277,7 +277,9 @@ module AESX
277
277
  # unless it's Base64 encoded?
278
278
  parts = encrypted_data.split('$')
279
279
  if parts.size.between?(3, 4)
280
- all_base64 = parts.all? { |str| str.nil? || str.empty? || str =~ /^[A-Za-z0-9+\/=]*$/ }
280
+ all_base64 = parts.all? do |str|
281
+ str.nil? || str.empty? || str.gsub(/\s+/, '') =~ /\A[A-Za-z0-9+\/=]*\z/
282
+ end
281
283
  if all_base64
282
284
  opts[:format] = :base_64
283
285
  end
@@ -291,11 +293,11 @@ module AESX
291
293
  ciphertext_b64 = parts[1]
292
294
  auth_tag_b64 = parts[2] if parts.size >= 3 && !parts[2].nil? && !parts[2].empty?
293
295
  compression_code = parts[3] if parts.size >= 4
294
-
295
- iv = Base64.decode64(iv_b64)
296
- ciphertext = Base64.decode64(ciphertext_b64)
297
- auth_tag = auth_tag_b64 ? Base64.decode64(auth_tag_b64) : nil
298
-
296
+
297
+ iv = Base64.decode64(iv_b64.gsub(/\s+/, ''))
298
+ ciphertext = Base64.decode64(ciphertext_b64.gsub(/\s+/, ''))
299
+ auth_tag = auth_tag_b64 ? Base64.decode64(auth_tag_b64.gsub(/\s+/, '')) : nil
300
+
299
301
  # Determine compression algorithm from the code
300
302
  if compression_code && compression_code != "0"
301
303
  algorithm_id = compression_code.to_i
@@ -304,17 +306,17 @@ module AESX
304
306
  when :binary
305
307
  # Extract the first byte which contains IV and auth tag lengths
306
308
  lengths = encrypted_data.unpack1('C')
307
-
309
+
308
310
  # Extract the second byte which contains compression info
309
311
  compression_byte = encrypted_data.unpack('CC')[1]
310
-
312
+
311
313
  # Calculate IV length and auth tag length
312
314
  iv_len = ((lengths >> 5) & 0x07) + 7
313
315
  tag_len = lengths & 0x1F
314
-
316
+
315
317
  # Extract IV, ciphertext, and auth tag
316
318
  iv = encrypted_data[2, iv_len] # 2 bytes of header now
317
-
319
+
318
320
  if tag_len > 0
319
321
  auth_tag = encrypted_data[-tag_len, tag_len]
320
322
  # Ciphertext starts after header and IV, ends before auth tag
@@ -323,7 +325,7 @@ module AESX
323
325
  auth_tag = nil
324
326
  ciphertext = encrypted_data[(2 + iv_len)..]
325
327
  end
326
-
328
+
327
329
  # Get compression algorithm
328
330
  compression_algorithm = AESCompression::ID_TO_ALGORITHM[compression_byte] if compression_byte != 0
329
331
  else
@@ -340,7 +342,7 @@ module AESX
340
342
  @cipher.padding = opts[:padding] || @options[:padding]
341
343
 
342
344
  decrypted_data = @cipher.update(ciphertext) + @cipher.final
343
-
345
+
344
346
  # Apply decompression if data was compressed
345
347
  if compression_algorithm
346
348
  begin
@@ -374,7 +376,7 @@ module AESX
374
376
  def normalize_key(key, cipher = 'AES-256-GCM', iterations: 10000)
375
377
  key_length = CIPHER_SPECS[cipher.upcase][0]
376
378
  return key if key.bytesize == key_length
377
-
379
+
378
380
  if key.match?(/\A[0-9a-fA-F]+\z/) # is it a hex string?
379
381
  key = key.unpack('a2' * key_length).map { |x| x.hex }.pack('c' * key_length)
380
382
  else
@@ -383,7 +385,7 @@ module AESX
383
385
  # Use PBKDF2 for key derivation
384
386
  key = OpenSSL::PKCS5.pbkdf2_hmac(key,salt,iterations,key_length,OpenSSL::Digest::SHA256.new)
385
387
  end
386
-
388
+
387
389
  key
388
390
  end
389
391
 
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aesx
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tom lahti
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-03-03 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: openssl
@@ -100,7 +100,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
100
100
  - !ruby/object:Gem::Version
101
101
  version: '0'
102
102
  requirements: []
103
- rubygems_version: 3.6.5
103
+ rubygems_version: 3.6.8
104
104
  specification_version: 4
105
105
  summary: AES gem, but with GCM/CTR ciphers, compression, and more
106
106
  test_files: []