File Coverage

blib/lib/Crypt/KeyWrap.pm
Criterion Covered Total %
statement 232 236 98.3
branch 113 162 69.7
condition 24 35 68.5
subroutine 28 28 100.0
pod 12 12 100.0
total 409 473 86.4


line stmt bran cond sub pod time code
1             package Crypt::KeyWrap;
2              
3 23     23   1426398 use strict;
  23         46  
  23         880  
4 23     23   158 use warnings;
  23         38  
  23         1828  
5              
6             our $VERSION = '0.038';
7              
8 23     23   148 use Exporter 'import';
  23         42  
  23         2899  
9             our %EXPORT_TAGS = ( all => [qw(aes_key_wrap aes_key_unwrap gcm_key_wrap gcm_key_unwrap pbes2_key_wrap pbes2_key_unwrap ecdh_key_wrap ecdh_key_unwrap ecdhaes_key_wrap ecdhaes_key_unwrap rsa_key_wrap rsa_key_unwrap)] );
10             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
11             our @EXPORT = qw();
12              
13 23     23   248 use Carp;
  23         106  
  23         1724  
14 23     23   4956 use Crypt::Mode::ECB;
  23         175930  
  23         867  
15 23     23   10485 use Crypt::AuthEnc::GCM qw(gcm_encrypt_authenticate gcm_decrypt_verify);
  23         8945  
  23         1665  
16 23     23   4052 use Crypt::PRNG qw(random_bytes);
  23         8523  
  23         1279  
17 23     23   10927 use Crypt::KeyDerivation qw(pbkdf2);
  23         9617  
  23         1773  
18 23     23   4566 use Crypt::Digest qw(digest_data);
  23         7364  
  23         1320  
19 23     23   4630 use Crypt::Misc qw(decode_b64u encode_b64u);
  23         52988  
  23         1365  
20 23     23   127 use Config;
  23         38  
  23         86241  
21              
22             # JWS: https://tools.ietf.org/html/rfc7515
23             # JWE: https://tools.ietf.org/html/rfc7516
24             # JWK: https://tools.ietf.org/html/rfc7517
25             # JWA: https://tools.ietf.org/html/rfc7518 - !!! this is important !!!
26              
27             sub _LSB {
28 13034     13034   19719 my ($bytes, $data) = @_;
29 13034         16247 my $len = length $data;
30 13034 50       38052 return $len > $bytes ? substr($data, $len-$bytes, $bytes) : $data;
31             }
32              
33             sub _MSB {
34 13034     13034   20569 my ($bytes, $data) = @_;
35 13034         16677 my $len = length $data;
36 13034 50       29888 return $len > $bytes ? substr($data, 0, $bytes) : $data;
37             }
38              
39             sub _N2RAW {
40 13020     13020   19976 my ($bytes, $n) = @_;
41 13020 100       22029 if ($bytes == 8) {
42 11148 50       54302 return pack("N", 0) . pack("N", $n) if $Config{uvsize} == 4; #workaround
43 11148         46545 return pack("N", $n >> 32) . pack("N", $n & 0xFFFFFFFF);
44             }
45 1872 50       5909 return pack("N", $n & 0xFFFFFFFF) if $bytes == 4;
46             }
47              
48             sub _decode_ecdh_info {
49 149     149   345 my ($name, $value) = @_;
50 149 100       675 return '' unless defined $value;
51 7 50       15 croak "concat_kdf: invalid $name" if ref $value;
52 7         19 my $decoded = decode_b64u($value);
53 7 100 66     367 croak "concat_kdf: invalid $name" unless defined $decoded && encode_b64u($decoded) eq $value;
54 6         12 return $decoded;
55             }
56              
57             sub aes_key_wrap {
58 148     148 1 537435 my ($kek, $pt_data, $cipher, $padding, $inverse) = @_;
59 148 100       519 $cipher = 'AES' unless defined $cipher;
60 148 50       387 $padding = $cipher eq 'AES' ? 1 : 0 unless defined $padding;
    100          
61              
62 148         302 my ($A, $B, $P, $R);
63              
64 148 50       467 croak "aes_key_wrap: no KEK" unless defined $kek;
65 148 50       334 croak "aes_key_wrap: no PT data" unless defined $pt_data;
66 148         314 my $klen = length $kek;
67 148 50 100     940 croak "aes_key_wrap: invalid KEK length" unless $klen == 16 || $klen == 24 || $klen == 32;
      66        
68 148 50 66     483 croak "aes_key_wrap: cipher must be AES or DES_EDE" unless $cipher eq 'AES' || $cipher eq 'DES_EDE';
69 148 50 66     540 croak "aes_key_wrap: padding not allowed with DES_EDE" if $padding && $cipher eq 'DES_EDE';
70              
71 148         2277 my $ECB = Crypt::Mode::ECB->new($cipher, 0);
72 148 100       564 my $blck = $cipher eq 'DES_EDE' ? 4 : 8; # semiblock size in bytes, for AES 8, for 3DES 4
73              
74             # IV selection per RFC 3394 (KW, no padding) vs RFC 5649 (KWP, with padding).
75             # Strict semantics: KWP always uses the alternate IV (A65959A6 || msg-len),
76             # even when the message is already aligned, and KW always uses the standard
77             # all-A6 IV. This matches the strict-mode behaviour Wycheproof tests for.
78 148         237 my $len = length $pt_data;
79 148         262 my $IV;
80 148 100       331 if ($padding) {
81 34 50       78 croak "aes_key_wrap: KWP only defined for AES (blck=8)" if $blck != 8;
82 34         98 $IV = pack("H*", "A65959A6") . pack("N", $len);
83 34 50       87 if ($len % $blck > 0) {
84 34         97 $pt_data .= chr(0) x ($blck - ($len % $blck));
85             }
86             }
87             else {
88 114 50       398 croak "aes_key_wrap: pt_data length not multiply of $blck" if $len % $blck != 0;
89 114         619 $IV = pack("H*", "A6" x $blck);
90             }
91              
92 148         471 my $n = length($pt_data) / $blck;
93 148         1753 $P->[$_] = substr($pt_data, $_*$blck, $blck) for (0..$n-1);
94              
95 148 100       445 if ($n == 1) {
96 14 100       79 return $inverse ? $ECB->decrypt($IV . $P->[0], $kek)
97             : $ECB->encrypt($IV . $P->[0], $kek);
98             }
99              
100 134         237 $A = $IV;
101 134         1081 $R->[$_] = $P->[$_] for (0..$n-1);
102              
103 134         290 for my $j (0..5) {
104 804         1678 for my $i (0..$n-1) {
105 6162 100       17476 $B = $inverse ? $ECB->decrypt($A . $R->[$i], $kek)
106             : $ECB->encrypt($A . $R->[$i], $kek);
107 6162         85054 $A = _MSB($blck, $B) ^ _N2RAW($blck, ($n*$j)+$i+1);
108 6162         12105 $R->[$i] = _LSB($blck, $B);
109             }
110             }
111              
112 134         222 my $rv = $A;
113 134         797 $rv .= $R->[$_] for (0..$n-1);
114 134         1796 return $rv;
115             }
116              
117             sub aes_key_unwrap {
118 186     186 1 68760 my ($kek, $ct_data, $cipher, $padding, $inverse) = @_;
119 186 100       7788 $cipher = 'AES' unless defined $cipher;
120 186 50       500 $padding = $cipher eq 'AES' ? 1 : 0 unless defined $padding;
    100          
121              
122 186         347 my ($A, $B, $C, $P, $R);
123              
124 186 50       529 croak "aes_key_unwrap: no KEK" unless defined $kek;
125 186 50       442 croak "aes_key_unwrap: no CT data" unless defined $ct_data;
126 186         383 my $klen = length $kek;
127 186 50 100     1029 croak "aes_key_unwrap: invalid KEK length" unless $klen == 16 || $klen == 24 || $klen == 32;
      66        
128 186 50 66     669 croak "aes_key_unwrap: cipher must be AES or DES_EDE" unless $cipher eq 'AES' || $cipher eq 'DES_EDE';
129 186 50 66     688 croak "aes_key_unwrap: padding not allowed with DES_EDE" if $padding && $cipher eq 'DES_EDE';
130              
131 186         2500 my $ECB = Crypt::Mode::ECB->new($cipher, 0);
132 186 100       596 my $blck = $cipher eq 'DES_EDE' ? 4 : 8; # semiblock size in bytes, for AES 8, for 3DES 4
133              
134             # Wrapped data must be at least IV + 1 semiblock and an exact semiblock
135             # multiple. Catches empty messages and trailing-byte tampering early.
136 186         331 my $ct_len = length $ct_data;
137 186 50       523 croak "aes_key_unwrap: ct too short ($ct_len bytes, need at least " . (2*$blck) . ")" if $ct_len < 2 * $blck;
138 186 50       536 croak "aes_key_unwrap: ct length not a multiple of $blck" if $ct_len % $blck != 0;
139              
140 186         533 my $n = $ct_len / $blck - 1;
141 186         1970 $C->[$_] = substr($ct_data, $_*$blck, $blck) for (0..$n); # n+1 semiblocks
142              
143 186 100       491 if ($n==1) {
144 14 100       81 $B = $inverse ? $ECB->encrypt($C->[0] . $C->[1], $kek)
145             : $ECB->decrypt($C->[0] . $C->[1], $kek);
146 14         271 $A = _MSB($blck, $B);
147 14         36 $R->[0] = _LSB($blck, $B);
148             }
149             else {
150 172         391 $A = $C->[0];
151 172         1379 $R->[$_] = $C->[$_+1] for (0..$n-1);
152 172         571 for(my $j=5; $j>=0; $j--) {
153 1032         2192 for(my $i=$n-1; $i>=0; $i--) {
154 6858 100       15402 $B = $inverse ? $ECB->encrypt(($A ^ _N2RAW($blck, $n*$j+$i+1)) . $R->[$i], $kek)
155             : $ECB->decrypt(($A ^ _N2RAW($blck, $n*$j+$i+1)) . $R->[$i], $kek);
156 6858         89641 $A = _MSB($blck, $B);
157 6858         11451 $R->[$i] = _LSB($blck, $B);
158             }
159             }
160             }
161              
162 186         354 my $rv = '';
163 186         1116 $rv .= $R->[$_] for (0..$n-1);
164              
165             # IV strictness: KW (padding=0) requires the standard all-A6 IV; KWP
166             # (padding=1) requires the alternate A65959A6||len IV. Each mode rejects
167             # the other's IV form.
168 186         703 my $A_hex = unpack("H*", $A);
169 186 100       490 if (!$padding) {
170 152 50       620 croak "aes_key_unwrap: unexpected IV [$A_hex] (KW expects all-A6)" unless $A_hex eq 'a6'x$blck;
171 152         6808 return $rv;
172             }
173 34 50       73 croak "aes_key_unwrap: KWP only defined for AES (blck=8)" if $blck != 8;
174 34 50       114 croak "aes_key_unwrap: unexpected IV [$A_hex] (KWP expects A65959A6 prefix)" unless $A_hex =~ /^a65959a6/;
175 34         79 my $msg_len = unpack("N", substr($A, 4, 4));
176 34         51 my $z = length($rv) - $msg_len;
177             # RFC 5649: 0 <= z < 8 (0 .. 7 zero pad bytes); msg_len must be at least 1.
178 34 50 33     217 croak "aes_key_unwrap: invalid length" if $msg_len < 1 || $z < 0 || $z > 7;
      33        
179             # Note: substr($rv, -0) returns the whole string, not empty; guard $z==0.
180 34 50       97 my $tail = $z > 0 ? unpack("H*", substr($rv, -$z)) : "";
181 34 50       87 croak "aes_key_unwrap: invalid data" unless $tail eq "00"x$z;
182 34         462 return substr($rv, 0, $msg_len);
183             }
184              
185             # AES GCM KW - https://tools.ietf.org/html/rfc7518#section-4.7
186              
187             sub gcm_key_wrap {
188 19     19 1 1286 my ($kek, $pt_data, $aad, $cipher, $iv) = @_;
189 19 100       56 $cipher = 'AES' unless defined $cipher;
190 19 100       72 $iv = random_bytes(12) unless defined $iv; # 96 bits REQUIRED by RFC7518
191 19         534 my ($ct_data, $tag) = gcm_encrypt_authenticate($cipher, $kek, $iv, $aad, $pt_data);
192 19         92 return ($ct_data, $tag, $iv);
193             }
194              
195             sub gcm_key_unwrap {
196 23     23 1 217787 my ($kek, $ct_data, $tag, $iv, $aad, $cipher) = @_;
197 23   100     108 $cipher ||= 'AES';
198 23         293 my $pt_data = gcm_decrypt_verify($cipher, $kek, $iv, $aad, $ct_data, $tag);
199 23         109 return $pt_data;
200             }
201              
202             # PBES2/PBKDF2 KW - https://tools.ietf.org/html/rfc7518#section-4.8
203              
204             sub pbes2_key_wrap {
205 27     27 1 1467 my ($kek, $pt_data, $alg, $salt, $iter) = @_;
206 27         52 my ($hash_name, $len);
207 27 50       176 if ($alg =~ /^PBES2-HS(256|384|512)\+A(128|192|256)KW$/) {
208 27         92 $hash_name = "SHA$1";
209 27         82 $len = $2/8;
210 27         515926 my $aes_key = pbkdf2($kek, $alg."\x00".$salt, $iter, $hash_name, $len);
211             # RFC 7518 sec 4.8 wraps via "AES Key Wrap algorithm specified in RFC 3394"
212 27         271 my $ct_data = aes_key_wrap($aes_key, $pt_data, 'AES', 0);
213 27         167 return $ct_data;
214             }
215 0         0 croak "pbes2_key_wrap: invalid alg '$alg'";
216 0         0 return undef;
217             }
218              
219             sub pbes2_key_unwrap {
220 50     50 1 243598 my ($kek, $ct_data, $alg, $salt, $iter) = @_;
221 50         99 my ($hash_name, $len);
222 50 50       336 if ($alg =~ /^PBES2-HS(256|384|512)\+A(128|192|256)KW$/) {
223 50         230 $hash_name = "SHA$1";
224 50         217 $len = $2/8;
225 50         969281 my $aes_key = pbkdf2($kek, $alg."\x00".$salt, $iter, $hash_name, $len);
226 50         557 my $pt_data = aes_key_unwrap($aes_key, $ct_data, 'AES', 0);
227 50         429 return $pt_data;
228             }
229 0         0 croak "pbes2_key_unwrap: invalid alg '$alg'";
230 0         0 return undef;
231             }
232              
233             # RSA KW
234             # https://tools.ietf.org/html/rfc7518#section-4.2
235             # https://tools.ietf.org/html/rfc7518#section-4.3
236              
237             sub rsa_key_wrap {
238 21     21 1 2814 my ($kek_public, $pt_data, $alg) = @_;
239 21 50       68 croak "rsa_key_wrap: no Crypt::PK::RSA" unless ref $kek_public eq 'Crypt::PK::RSA';
240 21         37 my ($padding, $hash_name);
241 21 100       77 if ($alg eq 'RSA-OAEP') { ($padding, $hash_name) = ('oaep', 'SHA1') }
  7 100       15  
    50          
242 7         14 elsif ($alg eq 'RSA-OAEP-256') { ($padding, $hash_name) = ('oaep', 'SHA256') }
243 7         16 elsif ($alg eq 'RSA1_5') { $padding = 'v1.5' }
244 21 50       49 croak "rsa_key_wrap: invalid algorithm '$alg'" unless $padding;
245 21         7039 my $ct_data = $kek_public->encrypt($pt_data, $padding, $hash_name);
246 21         131 return $ct_data;
247             }
248              
249             sub rsa_key_unwrap {
250 45     45 1 173538 my ($kek_private, $ct_data, $alg) = @_;
251 45 50       171 croak "rsa_key_unwrap: no Crypt::PK::RSA" unless ref $kek_private eq 'Crypt::PK::RSA';
252 45 50       197 croak "rsa_key_unwrap: no private key" unless $kek_private->is_private;
253 45         69 my ($padding, $hash_name);
254 45 100       188 if ($alg eq 'RSA-OAEP') { ($padding, $hash_name) = ('oaep', 'SHA1') }
  16 100       36  
    50          
255 10         22 elsif ($alg eq 'RSA-OAEP-256') { ($padding, $hash_name) = ('oaep', 'SHA256') }
256 19         44 elsif ($alg eq 'RSA1_5') { $padding = 'v1.5' }
257 45 50       89 croak "rsa_key_unwrap: invalid algorithm '$alg'" unless $padding;
258 45         333129 my $pt_data = $kek_private->decrypt($ct_data, $padding, $hash_name);
259 45         1023 return $pt_data;
260             }
261              
262             # ConcatKDF - http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Ar2.pdf
263             # ECDH KW - https://tools.ietf.org/html/rfc7518#section-4.6
264              
265             sub _concat_kdf {
266 75     75   471 my ($hash_name, $key_size, $shared_secret, $algorithm, $apu, $apv) = @_;
267 75         325 $apu = _decode_ecdh_info('apu', $apu);
268 74         220 $apv = _decode_ecdh_info('apv', $apv);
269 74         697 my $hsize = Crypt::Digest->hashsize($hash_name);
270 74         269 my $count = int($key_size / $hsize);
271 74 100       303 $count++ if ($key_size % $hsize) > 0;
272 74         166 my $data = '';
273 74         269 for my $i (1..$count) {
274 80         1616 $data .= digest_data($hash_name, pack("N", $i) .
275             $shared_secret .
276             pack("N", length($algorithm)) . $algorithm .
277             pack("N", length($apu)) . $apu .
278             pack("N", length($apv)) . $apv .
279             pack("N", 8 *$key_size));
280             }
281 74         350 return substr($data, 0, $key_size);
282             }
283              
284             sub ecdh_key_wrap {
285 7     7 1 7097 my ($kek_public, $enc, $apu, $apv) = @_;
286 7 50       35 croak "ecdh_key_wrap: no Crypt::PK::ECC" unless ref $kek_public eq 'Crypt::PK::ECC';
287 7         17 my $encryption_key_size = 256;
288 7 100       34 if ($enc =~ /^A(128|192|256)CBC-HS/) {
289 3         13 $encryption_key_size = $1*2;
290             }
291 7 100       39 if ($enc =~ /^A(128|192|256)GCM/) {
292 4         14 $encryption_key_size = $1;
293             }
294 7         44 my $ephemeral = Crypt::PK::ECC->new()->generate_key($kek_public->curve2hash);
295 7         81216 my $shared_secret = $ephemeral->shared_secret($kek_public);
296 7         77 my $ct_data = _concat_kdf('SHA256', $encryption_key_size/8, $shared_secret, $enc, $apu, $apv);
297 7         58 return ($ct_data, $ephemeral->export_key_jwk('public'));
298             }
299              
300             sub ecdh_key_unwrap {
301 21     21 1 456526 my ($kek_private, $enc, $epk, $apu, $apv) = @_;
302 21 50       80 croak "ecdh_key_unwrap: no Crypt::PK::ECC" unless ref $kek_private eq 'Crypt::PK::ECC';
303 21 50       128 croak "ecdh_key_unwrap: no private key" unless $kek_private->is_private;
304 21         53 my $encryption_key_size = 256;
305 21 100       90 if ($enc =~ /^A(128|192|256)CBC-HS/) {
306 7         32 $encryption_key_size = $1*2;
307             }
308 21 100       139 if ($enc =~ /^A(128|192|256)GCM/) {
309 14         39 $encryption_key_size = $1;
310             }
311 21 100       178 my $ephemeral = ref($epk) eq 'Crypt::PK::ECC' ? $epk : Crypt::PK::ECC->new(ref $epk ? $epk : \$epk);
    50          
312 21         193443 my $shared_secret = $kek_private->shared_secret($ephemeral);
313 21         213 my $pt_data = _concat_kdf('SHA256', $encryption_key_size/8, $shared_secret, $enc, $apu, $apv);
314 20         1048 return $pt_data;
315             }
316              
317             sub ecdhaes_key_wrap {
318 20     20 1 5204 my ($kek_public, $pt_data, $alg, $apu, $apv) = @_;
319 20 50       129 croak "ecdhaes_key_wrap: no Crypt::PK::(ECC|X25519)" unless ref($kek_public) =~ /^Crypt::PK::(ECC|X25519)$/;
320 20         46 my $encryption_key_size = 256;
321 20 50       105 if ($alg =~ /^ECDH-ES\+A(128|192|256)KW$/) {
322 20         65 $encryption_key_size = $1;
323             }
324 20         27 my $ephemeral;
325 20 100       73 if (ref($kek_public) eq 'Crypt::PK::ECC') {
326 19         118 $ephemeral = Crypt::PK::ECC->new->generate_key($kek_public->curve2hash);
327             }
328             else {
329 1         5 $ephemeral = Crypt::PK::X25519->new->generate_key();
330             }
331 20         384961 my $shared_secret = $ephemeral->shared_secret($kek_public);
332 20         256 my $kek = _concat_kdf('SHA256', $encryption_key_size/8, $shared_secret, $alg, $apu, $apv);
333             # RFC 7518 sec 4.6 wraps via "AES Key Wrap algorithm specified in RFC 3394"
334 20         97 return (aes_key_wrap($kek, $pt_data, 'AES', 0), $ephemeral->export_key_jwk('public'));
335             }
336              
337             sub ecdhaes_key_unwrap {
338 27     27 1 190254 my ($kek_private, $ct_data, $alg, $epk, $apu, $apv) = @_;
339 27 50       287 croak "ecdhaes_key_unwrap: no Crypt::PK::(ECC|X25519)" unless ref($kek_private) =~ /^Crypt::PK::(ECC|X25519)$/;
340 27 50       289 croak "ecdhaes_key_unwrap: no private key" unless $kek_private->is_private;
341 27         71 my $encryption_key_size = 256;
342 27 50       155 if ($alg =~ /^ECDH-ES\+A(128|192|256)KW$/) {
343 27         84 $encryption_key_size = $1;
344             }
345 27         58 my $ephemeral;
346 27 100       89 if (ref($kek_private) eq 'Crypt::PK::ECC') {
347 26 100       208 $ephemeral = ref($epk) eq 'Crypt::PK::ECC' ? $epk : Crypt::PK::ECC->new(ref $epk ? $epk : \$epk);
    50          
348             }
349             else {
350 1 50       9 $ephemeral = ref($epk) eq 'Crypt::PK::X25519' ? $epk : Crypt::PK::X25519->new(ref $epk ? $epk : \$epk);
    50          
351             }
352 27         429013 my $shared_secret = $kek_private->shared_secret($ephemeral);
353 27         325 my $kek = _concat_kdf('SHA256', $encryption_key_size/8, $shared_secret, $alg, $apu, $apv);
354 27         138 my $pt_data = aes_key_unwrap($kek, $ct_data, 'AES', 0);
355 27         1468 return $pt_data;
356             }
357              
358             1;
359              
360             =pod
361              
362             =head1 NAME
363              
364             Crypt::KeyWrap - Key management/wrapping algorithms defined in RFC7518 (JWA)
365              
366             =head1 SYNOPSIS
367              
368             # A192KW wrapping
369             use Crypt::KeyWrap qw(aes_key_wrap);
370             my $kek = pack("H*", "5840df6e29b02af1ab493b705bf16ea1ae8338f4dcc176a8"); # key encryption key
371             my $cek = pack("H*", "c37b7e6492584340bed12207808941155068f738"); # content encryption key
372             my $enc_cek = aes_key_wrap($kek, $pt_data); # encrypted content encryption key
373              
374             # A192KW unwrapping
375             use Crypt::KeyWrap qw(aes_key_unwrap);
376             my $kek = pack("H*", "5840df6e29b02af1ab493b705bf16ea1ae8338f4dcc176a8");
377             my $enc_cek = pack("H*", "138bdeaa9b8fa7fc61f97742e72248ee5ae6ae5360d1ae6a5f54f373fa543b6a");
378             my $cek = aes_key_unwrap($kek, $enc_cek);
379              
380             =head1 DESCRIPTION
381              
382             Implements key management algorithms defined in L.
383              
384             These functions are the low-level primitives that L dispatches
385             to when handling JWE C values. If you are building or consuming JWE
386             tokens, use L instead - it covers algorithm selection, header
387             handling, and serialization on top of these wrappers.
388              
389             BEWARE: experimental, interface of this module might change!
390              
391             Supported algorithms (all defined in RFC7518):
392              
393             A128KW see: aes_key_wrap() + aes_key_unwrap()
394             A192KW see: aes_key_wrap() + aes_key_unwrap()
395             A256KW see: aes_key_wrap() + aes_key_unwrap()
396             A128GCMKW see: gcm_key_wrap() + gcm_key_unwrap()
397             A192GCMKW see: gcm_key_wrap() + gcm_key_unwrap()
398             A256GCMKW see: gcm_key_wrap() + gcm_key_unwrap()
399             PBES2-HS256+A128KW see: pbes2_key_wrap() + pbes2_key_unwrap()
400             PBES2-HS384+A192KW see: pbes2_key_wrap() + pbes2_key_unwrap()
401             PBES2-HS512+A256KW see: pbes2_key_wrap() + pbes2_key_unwrap()
402             RSA-OAEP see: rsa_key_wrap() + rsa_key_unwrap()
403             RSA-OAEP-256 see: rsa_key_wrap() + rsa_key_unwrap()
404             RSA1_5 see: rsa_key_wrap() + rsa_key_unwrap()
405             ECDH-ES+A128KW see: ecdhaes_key_wrap() + ecdhaes_key_unwrap()
406             ECDH-ES+A192KW see: ecdhaes_key_wrap() + ecdhaes_key_unwrap()
407             ECDH-ES+A256KW see: ecdhaes_key_wrap() + ecdhaes_key_unwrap()
408             ECDH-ES see: ecdh_key_wrap() + ecdh_key_unwrap()
409              
410             =head1 EXPORT
411              
412             Nothing is exported by default.
413              
414             You can export selected functions:
415              
416             use Crypt::KeyWrap qw(aes_key_wrap gcm_key_wrap pbes2_key_wrap);
417              
418             Or all of them at once:
419              
420             use Crypt::KeyWrap ':all';
421              
422             =head1 FUNCTIONS
423              
424             =head2 aes_key_wrap
425              
426             AES Key Wrap. Implements C, C, C from RFC 7518
427             section 4.4 (L) and the
428             underlying RFC 3394 (L) and RFC 5649
429             (L) constructions. Also compatible
430             with NIST SP 800-38F (KW, KWP, and TDEA/DES_EDE-based TKW).
431              
432             $enc_cek = aes_key_wrap($kek, $cek);
433             # or
434             $enc_cek = aes_key_wrap($kek, $cek, $cipher, $padding, $inverse);
435              
436             # params:
437             # $kek .. key encryption key (16 bytes for AES128, 24 for AES192, 32 for AES256)
438             # $cek .. content encryption key
439             # optional params:
440             # $cipher .. 'AES' (default) or 'DES_EDE'
441             # $padding .. 1 (default) -> KWP (RFC 5649): always uses the alternate
442             # IV (A65959A6 || msg-len) and pads $cek to a multiple of 8
443             # (relevant for AES only)
444             # 0 -> KW (RFC 3394): uses the standard all-A6 IV; $cek must
445             # already be a multiple of 8 (AES) or 4 (DES_EDE)
446             # $inverse .. 0 (default) or 1 - use cipher in inverse mode as defined by SP 800-38F
447              
448             C<$enc_cek>, C<$cek>, and C<$kek> are binary octets.
449              
450             B KW (C<$padding=0>) and KWP (C<$padding=1>) are strictly
451             separated; KWP always emits the alternate IV even for already-aligned
452             input. JWE callers (A*KW, PBES2-*+A*KW, ECDH-ES+A*KW) all use C<$padding=0>
453             per RFC 7518.
454              
455             =head2 aes_key_unwrap
456              
457             AES Key Unwrap. Inverse of L; implements C,
458             C, C from RFC 7518 section 4.4
459             (L).
460              
461             $cek = aes_key_unwrap($kek, $enc_cek);
462             # or
463             $cek = aes_key_unwrap($kek, $enc_cek, $cipher, $padding, $inverse);
464              
465             # params:
466             # $kek .. key encryption key (16 bytes for AES128, 24 for AES192, 32 for AES256)
467             # $enc_cek .. encrypted content encryption key
468             # optional params:
469             # $cipher .. 'AES' (default) or 'DES_EDE'
470             # $padding .. 1 (default) -> KWP (RFC 5649): expects the alternate IV
471             # (A65959A6 || msg-len) and strips zero padding
472             # (relevant for AES only)
473             # 0 -> KW (RFC 3394): expects the standard all-A6 IV
474             # $inverse .. 0 (default) or 1 - use cipher in inverse mode as defined by SP 800-38F
475              
476             C<$enc_cek>, C<$cek>, and C<$kek> are binary octets.
477              
478             B The two modes are strict and reject the other mode's IV
479             form. Croaks with C or C
480             multiple of $blck> on malformed input lengths.
481              
482             =head2 gcm_key_wrap
483              
484             AES GCM key wrap algorithm as defined in L
485             (implements algorithms C, C, C).
486              
487             ($enc_cek, $tag, $iv) = gcm_key_wrap($kek, $cek);
488             #or
489             ($enc_cek, $tag, $iv) = gcm_key_wrap($kek, $cek, $aad);
490             #or
491             ($enc_cek, $tag, $iv) = gcm_key_wrap($kek, $cek, $aad, $cipher, $iv);
492              
493             # params:
494             # $kek .. key encryption key (16bytes for AES128, 24 for AES192, 32 for AES256)
495             # $cek .. content encryption key
496             # optional params:
497             # $aad .. additional authenticated data, default: '' (empty string)
498             # $cipher .. cipher to be used by GCM, default: 'AES'
499             # $iv .. initialization vector (if not defined a random IV is generated)
500              
501             Values C<$enc_cek>, C<$cek>, C<$aad>, C<$iv>, C<$tag> and C<$kek> are binary octets.
502              
503             =head2 gcm_key_unwrap
504              
505             AES GCM key unwrap algorithm as defined in L
506             (implements algorithms C, C, C).
507              
508             $cek = gcm_key_unwrap($kek, $enc_cek, $tag, $iv);
509             # or
510             $cek = gcm_key_unwrap($kek, $enc_cek, $tag, $iv, $aad);
511             # or
512             $cek = gcm_key_unwrap($kek, $enc_cek, $tag, $iv, $aad, $cipher);
513              
514             # params:
515             # $kek .. key encryption key (16bytes for AES128, 24 for AES192, 32 for AES256)
516             # $enc_cek .. encrypted content encryption key
517             # $tag .. GCM's tag
518             # $iv .. initialization vector
519             # optional params:
520             # $aad .. additional authenticated data, default: '' (empty string)
521             # $cipher .. cipher to be used by GCM, default: 'AES'
522              
523             Values C<$enc_cek>, C<$cek>, C<$aad>, C<$iv>, C<$tag> and C<$kek> are binary octets.
524              
525             =head2 pbes2_key_wrap
526              
527             PBES2 key wrap algorithm as defined in L
528             (implements algorithms C, C, C).
529              
530             $enc_cek = pbes2_key_wrap($kek, $cek, $alg, $salt, $iter);
531              
532             # params:
533             # $kek .. key encryption key (arbitrary length)
534             # $cek .. content encryption key
535             # $alg .. algorithm name e.g. 'PBES2-HS256+A128KW' (see rfc7518)
536             # $salt .. pbkdf2 salt
537             # $iter .. pbkdf2 iteration count
538              
539             Values C<$enc_cek>, C<$cek>, C<$salt> and C<$kek> are binary octets.
540              
541             =head2 pbes2_key_unwrap
542              
543             PBES2 key unwrap algorithm. Inverse of L; implements
544             C, C, C from
545             RFC 7518 section 4.8 (L).
546              
547             $cek = pbes2_key_unwrap($kek, $enc_cek, $alg, $salt, $iter);
548              
549             # params:
550             # $kek .. key encryption key (arbitrary length)
551             # $enc_cek .. encrypted content encryption key
552             # $alg .. algorithm name e.g. 'PBES2-HS256+A128KW' (see rfc7518)
553             # $salt .. pbkdf2 salt
554             # $iter .. pbkdf2 iteration count
555              
556             Values C<$enc_cek>, C<$cek>, C<$salt> and C<$kek> are binary octets.
557              
558             =head2 rsa_key_wrap
559              
560             RSA key wrap algorithm. Implements C, C, and
561             C from RFC 7518 sections 4.2 and 4.3
562             (L,
563             L).
564              
565             $enc_cek = rsa_key_wrap($kek, $cek, $alg);
566              
567             # params:
568             # $kek .. RSA public key - Crypt::PK::RSA instance
569             # $cek .. content encryption key
570             # $alg .. algorithm name e.g. 'RSA-OAEP' (see rfc7518)
571              
572             Values C<$enc_cek> and C<$cek> are binary octets.
573              
574             =head2 rsa_key_unwrap
575              
576             RSA key unwrap algorithm. Inverse of L; implements
577             C, C, and C from RFC 7518 sections 4.2 and 4.3.
578              
579             $cek = rsa_key_unwrap($kek, $enc_cek, $alg);
580              
581             # params:
582             # $kek .. RSA private key - Crypt::PK::RSA instance
583             # $enc_cek .. encrypted content encryption key
584             # $alg .. algorithm name e.g. 'RSA-OAEP' (see rfc7518)
585              
586             Values C<$enc_cek> and C<$cek> are binary octets.
587              
588             =head2 ecdhaes_key_wrap
589              
590             ECDH+AESKW key agreement/wrap algorithm as defined in L
591             (implements algorithms C, C, C).
592              
593             ($enc_cek, $epk) = ecdhaes_key_wrap($kek, $cek, $alg, $apu, $apv);
594              
595             # params:
596             # $kek .. ECC public key - Crypt::PK::ECC|X25519 instance
597             # $cek .. content encryption key
598             # $alg .. algorithm name e.g. 'ECDH-ES+A256KW' (see rfc7518)
599             # optional params:
600             # $apu .. base64url-encoded Agreement PartyUInfo Header Parameter
601             # $apv .. base64url-encoded Agreement PartyVInfo Header Parameter
602              
603             Values C<$enc_cek> and C<$cek> are binary octets.
604              
605             =head2 ecdhaes_key_unwrap
606              
607             ECDH+AESKW key agreement/unwrap algorithm as defined in L
608             (implements algorithms C, C, C).
609              
610             $cek = ecdhaes_key_unwrap($kek, $enc_cek, $alg, $epk, $apu, $apv);
611              
612             # params:
613             # $kek .. ECC private key - Crypt::PK::ECC|X25519 instance
614             # $enc_cek .. encrypted content encryption key
615             # $alg .. algorithm name e.g. 'ECDH-ES+A256KW' (see rfc7518)
616             # $epk .. ephemeral ECC public key (JWK/JSON or Crypt::PK::ECC|X25519)
617             # optional params:
618             # $apu .. base64url-encoded Agreement PartyUInfo Header Parameter
619             # $apv .. base64url-encoded Agreement PartyVInfo Header Parameter
620              
621             Values C<$enc_cek> and C<$cek> are binary octets.
622              
623             =head2 ecdh_key_wrap
624              
625             ECDH (Ephemeral Static) key agreement/wrap algorithm as defined in L
626             (implements algorithm C).
627              
628             ($cek, $epk) = ecdh_key_wrap($kek, $enc, $apu, $apv);
629              
630             # params:
631             # $kek .. ECC public key - Crypt::PK::ECC|X25519 instance
632             # $enc .. encryption algorithm name e.g. 'A256GCM' (see rfc7518)
633             # optional params:
634             # $apu .. base64url-encoded Agreement PartyUInfo Header Parameter
635             # $apv .. base64url-encoded Agreement PartyVInfo Header Parameter
636              
637             C<$cek> is binary octets; C<$epk> is a JWK/JSON string with the ephemeral ECC public key.
638              
639             =head2 ecdh_key_unwrap
640              
641             ECDH (Ephemeral Static) key agreement/unwrap algorithm as defined in L
642             (implements algorithm C).
643              
644             $cek = ecdh_key_unwrap($kek, $enc, $epk, $apu, $apv);
645              
646             # params:
647             # $kek .. ECC private key - Crypt::PK::ECC|X25519 instance
648             # $enc .. encryption algorithm name e.g. 'A256GCM' (see rfc7518)
649             # $epk .. ephemeral ECC public key (JWK/JSON or Crypt::PK::ECC|X25519)
650             # optional params:
651             # $apu .. base64url-encoded Agreement PartyUInfo Header Parameter
652             # $apv .. base64url-encoded Agreement PartyVInfo Header Parameter
653              
654             Value C<$cek> - binary octets.
655              
656             =head1 SEE ALSO
657              
658             L, L, L, L, L
659              
660             =head1 LICENSE
661              
662             This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
663              
664             =head1 COPYRIGHT
665              
666             Copyright (c) 2015-2026 DCIT, a.s. L / Karel Miko