philiprehberger-crypt 0.2.0 → 0.3.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 +4 -4
- data/CHANGELOG.md +7 -0
- data/README.md +13 -1
- data/lib/philiprehberger/crypt/version.rb +1 -1
- data/lib/philiprehberger/crypt.rb +32 -2
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9b8b7e1b7ba025acb109315c7917651f67b9645ef6abc1f7699dbe4e471020b2
|
|
4
|
+
data.tar.gz: 988b00641592540f69b355896dd6d524f7369830f93a33ad450909e4260671a2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 85775a37db94d000bd73b20ed1d403e6dc5b891e38600860aea6ce0087c1c45d680886b3efc5212258b4f9132a691e7d52a92d1b2e824c935a698737f3590591
|
|
7
|
+
data.tar.gz: 799433a04830123ffe629edaf5460dcad49f477e48108c66c7cbb1bbfb7c7611e78c9cf77f97cd7211de060b036d93eec7119e49cd7b1626f9af8a7aff47864e
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.3.0] - 2026-04-09
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- `hmac(data, key:, algorithm:)` for computing HMAC signatures (SHA-256/384/512)
|
|
14
|
+
- `hmac_verify(data, signature:, key:, algorithm:)` for constant-time HMAC verification
|
|
15
|
+
- `derive_key` now accepts an `iterations:` keyword to configure PBKDF2 work factor
|
|
16
|
+
|
|
10
17
|
## [0.2.0] - 2026-04-03
|
|
11
18
|
|
|
12
19
|
### Added
|
data/README.md
CHANGED
|
@@ -96,6 +96,16 @@ Philiprehberger::Crypt.random_bytes(32)
|
|
|
96
96
|
# => 32-byte binary string
|
|
97
97
|
```
|
|
98
98
|
|
|
99
|
+
### HMAC Signing
|
|
100
|
+
|
|
101
|
+
```ruby
|
|
102
|
+
key = Philiprehberger::Crypt.random_hex(16)
|
|
103
|
+
signature = Philiprehberger::Crypt.hmac("payload", key: key)
|
|
104
|
+
|
|
105
|
+
Philiprehberger::Crypt.hmac_verify("payload", signature: signature, key: key)
|
|
106
|
+
# => true
|
|
107
|
+
```
|
|
108
|
+
|
|
99
109
|
### Secure Comparison
|
|
100
110
|
|
|
101
111
|
```ruby
|
|
@@ -112,7 +122,9 @@ Philiprehberger::Crypt.secure_compare(token_a, token_b)
|
|
|
112
122
|
| `.rotate_key(encrypted, old_key:, new_key:)` | Re-encrypt data with a new key |
|
|
113
123
|
| `.envelope_encrypt(data, master_key:)` | Envelope encrypt with random data key |
|
|
114
124
|
| `.envelope_decrypt(envelope, master_key:)` | Decrypt envelope-encrypted data |
|
|
115
|
-
| `.derive_key(password, salt:)` | Derive a 32-byte key using PBKDF2-HMAC-SHA256 |
|
|
125
|
+
| `.derive_key(password, salt:, iterations:)` | Derive a 32-byte key using PBKDF2-HMAC-SHA256 |
|
|
126
|
+
| `.hmac(data, key:, algorithm:)` | Compute hex-encoded HMAC signature |
|
|
127
|
+
| `.hmac_verify(data, signature:, key:, algorithm:)` | Constant-time HMAC verification |
|
|
116
128
|
| `.random_salt` | Generate a 32-byte cryptographic random salt |
|
|
117
129
|
| `.random_token` | Generate a URL-safe Base64 random token |
|
|
118
130
|
| `.random_hex(n)` | Generate a hex-encoded random string (2*n characters) |
|
|
@@ -71,17 +71,47 @@ module Philiprehberger
|
|
|
71
71
|
#
|
|
72
72
|
# @param password [String] the password to derive from
|
|
73
73
|
# @param salt [String] a random salt (use {.random_salt} to generate)
|
|
74
|
+
# @param iterations [Integer] number of PBKDF2 iterations (default: 100_000)
|
|
74
75
|
# @return [String] a 32-byte raw key suitable for {.encrypt}/{.decrypt}
|
|
75
|
-
|
|
76
|
+
# @raise [ArgumentError] if iterations is less than 1
|
|
77
|
+
def self.derive_key(password, salt:, iterations: PBKDF2_ITERATIONS)
|
|
78
|
+
raise ArgumentError, 'iterations must be >= 1' if iterations.to_i < 1
|
|
79
|
+
|
|
76
80
|
OpenSSL::PKCS5.pbkdf2_hmac(
|
|
77
81
|
password.to_s,
|
|
78
82
|
salt,
|
|
79
|
-
|
|
83
|
+
iterations.to_i,
|
|
80
84
|
KEY_LENGTH,
|
|
81
85
|
OpenSSL::Digest.new('SHA256')
|
|
82
86
|
)
|
|
83
87
|
end
|
|
84
88
|
|
|
89
|
+
# Compute an HMAC signature for data using the given key.
|
|
90
|
+
#
|
|
91
|
+
# @param data [String] the data to sign
|
|
92
|
+
# @param key [String] the HMAC secret key
|
|
93
|
+
# @param algorithm [Symbol] hash algorithm (:sha256, :sha384, or :sha512)
|
|
94
|
+
# @return [String] hex-encoded HMAC digest
|
|
95
|
+
# @raise [ArgumentError] if algorithm is unsupported
|
|
96
|
+
def self.hmac(data, key:, algorithm: :sha256)
|
|
97
|
+
algo = HASH_ALGORITHMS[algorithm]
|
|
98
|
+
raise ArgumentError, "Unsupported algorithm: #{algorithm}. Use :sha256, :sha384, or :sha512" unless algo
|
|
99
|
+
|
|
100
|
+
OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new(algo), key.to_s, data.to_s)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Verify an HMAC signature in constant time.
|
|
104
|
+
#
|
|
105
|
+
# @param data [String] the original data
|
|
106
|
+
# @param signature [String] the expected hex-encoded HMAC signature
|
|
107
|
+
# @param key [String] the HMAC secret key
|
|
108
|
+
# @param algorithm [Symbol] hash algorithm used to sign
|
|
109
|
+
# @return [Boolean] true if the signature matches
|
|
110
|
+
def self.hmac_verify(data, signature:, key:, algorithm: :sha256)
|
|
111
|
+
expected = hmac(data, key: key, algorithm: algorithm)
|
|
112
|
+
secure_compare(expected, signature.to_s)
|
|
113
|
+
end
|
|
114
|
+
|
|
85
115
|
# Generate a cryptographically secure random salt.
|
|
86
116
|
#
|
|
87
117
|
# @return [String] a 32-byte random salt (raw bytes)
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: philiprehberger-crypt
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Philip Rehberger
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-04-
|
|
11
|
+
date: 2026-04-09 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: A high-level encryption toolkit providing AES-256-GCM encryption and
|
|
14
14
|
decryption, key rotation, envelope encryption, PBKDF2 key derivation, secure random
|