1package Crypt::KeyWrap; 2 3use strict; 4use warnings; 5 6our $VERSION = '0.034'; 7 8use Exporter 'import'; 9our %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)] ); 10our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); 11our @EXPORT = qw(); 12 13use Carp; 14use Crypt::Mode::ECB; 15use Crypt::AuthEnc::GCM qw(gcm_encrypt_authenticate gcm_decrypt_verify); 16use Crypt::PRNG qw(random_bytes); 17use Crypt::KeyDerivation qw(pbkdf2); 18use Crypt::Digest qw(digest_data); 19use Config; 20 21# JWS: https://tools.ietf.org/html/rfc7515 22# JWE: https://tools.ietf.org/html/rfc7516 23# JWK: https://tools.ietf.org/html/rfc7517 24# JWA: https://tools.ietf.org/html/rfc7518 - !!! this is important !!! 25 26sub _LSB { 27 my ($bytes, $data) = @_; 28 my $len = length $data; 29 return $len > $bytes ? substr($data, $len-$bytes, $bytes) : $data; 30} 31 32sub _MSB { 33 my ($bytes, $data) = @_; 34 my $len = length $data; 35 return $len > $bytes ? substr($data, 0, $bytes) : $data; 36} 37 38sub _N2RAW { 39 my ($bytes, $n) = @_; 40 if ($bytes == 8) { 41 return pack("N", 0) . pack("N", $n) if $Config{uvsize} == 4; #workaround 42 return pack("N", $n >> 32) . pack("N", $n & 0xFFFFFFFF); 43 } 44 return pack("N", $n & 0xFFFFFFFF) if $bytes == 4; 45} 46 47sub aes_key_wrap { 48 my ($kek, $pt_data, $cipher, $padding, $inverse) = @_; 49 $cipher = 'AES' unless defined $cipher; 50 $padding = $cipher eq 'AES' ? 1 : 0 unless defined $padding; 51 52 my ($A, $B, $P, $R); 53 54 croak "aes_key_wrap: no KEK" unless defined $kek; 55 croak "aes_key_wrap: no PT data" unless defined $pt_data; 56 my $klen = length $kek; 57 croak "aes_key_wrap: invalid KEK length" unless $klen == 16 || $klen == 24 || $klen == 32; 58 croak "aes_key_wrap: cipher must be AES or DES_EDE" unless $cipher eq 'AES' || $cipher eq 'DES_EDE'; 59 croak "aes_key_wrap: padding not allowed with DES_EDE" if $padding && $cipher eq 'DES_EDE'; 60 61 my $ECB = Crypt::Mode::ECB->new($cipher, 0); 62 my $blck = $cipher eq 'DES_EDE' ? 4 : 8; # semiblock size in bytes, for AES 8, for 3DES 4 63 64 my $IV = pack("H*", "A6" x $blck); 65 my $len = length $pt_data; 66 if ($len % $blck > 0) { 67 croak "aes_key_wrap: pt_data length not multiply of $blck" if !$padding; 68 $pt_data .= chr(0) x ($blck - ($len % $blck)); 69 $IV = pack("H*", "A65959A6") . pack("N", $len); 70 } 71 72 my $n = length($pt_data) / $blck; 73 $P->[$_] = substr($pt_data, $_*$blck, $blck) for (0..$n-1); 74 75 if ($n == 1) { 76 return $inverse ? $ECB->decrypt($IV . $P->[0], $kek) 77 : $ECB->encrypt($IV . $P->[0], $kek); 78 } 79 80 $A = $IV; 81 $R->[$_] = $P->[$_] for (0..$n-1); 82 83 for my $j (0..5) { 84 for my $i (0..$n-1) { 85 $B = $inverse ? $ECB->decrypt($A . $R->[$i], $kek) 86 : $ECB->encrypt($A . $R->[$i], $kek); 87 $A = _MSB($blck, $B) ^ _N2RAW($blck, ($n*$j)+$i+1); 88 $R->[$i] = _LSB($blck, $B); 89 } 90 } 91 92 my $rv = $A; 93 $rv .= $R->[$_] for (0..$n-1); 94 return $rv; 95} 96 97sub aes_key_unwrap { 98 my ($kek, $ct_data, $cipher, $padding, $inverse) = @_; 99 $cipher = 'AES' unless defined $cipher; 100 $padding = $cipher eq 'AES' ? 1 : 0 unless defined $padding; 101 102 my ($A, $B, $C, $P, $R); 103 104 croak "aes_key_unwrap: no KEK" unless defined $kek; 105 croak "aes_key_unwrap: no CT data" unless defined $ct_data; 106 my $klen = length $kek; 107 croak "aes_key_unwrap: invalid KEK length" unless $klen == 16 || $klen == 24 || $klen == 32; 108 croak "aes_key_unwrap: cipher must be AES or DES_EDE" unless $cipher eq 'AES' || $cipher eq 'DES_EDE'; 109 croak "aes_key_unwrap: padding not allowed with DES_EDE" if $padding && $cipher eq 'DES_EDE'; 110 111 my $ECB = Crypt::Mode::ECB->new($cipher, 0); 112 my $blck = $cipher eq 'DES_EDE' ? 4 : 8; # semiblock size in bytes, for AES 8, for 3DES 4 113 114 my $n = length($ct_data) / $blck - 1; 115 $C->[$_] = substr($ct_data, $_*$blck, $blck) for (0..$n); # n+1 semiblocks 116 117 if ($n==1) { 118 $B = $inverse ? $ECB->encrypt($C->[0] . $C->[1], $kek) 119 : $ECB->decrypt($C->[0] . $C->[1], $kek); 120 $A = _MSB($blck, $B); 121 $R->[0] = _LSB($blck, $B); 122 } 123 else { 124 $A = $C->[0]; 125 $R->[$_] = $C->[$_+1] for (0..$n-1); 126 for(my $j=5; $j>=0; $j--) { 127 for(my $i=$n-1; $i>=0; $i--) { 128 $B = $inverse ? $ECB->encrypt(($A ^ _N2RAW($blck, $n*$j+$i+1)) . $R->[$i], $kek) 129 : $ECB->decrypt(($A ^ _N2RAW($blck, $n*$j+$i+1)) . $R->[$i], $kek); 130 $A = _MSB($blck, $B); 131 $R->[$i] = _LSB($blck, $B); 132 } 133 } 134 } 135 136 my $rv = ''; 137 $rv .= $R->[$_] for (0..$n-1); 138 139 my $A_hex = unpack("H*", $A); 140 if ($A_hex eq 'a6'x$blck) { 141 return $rv; 142 } 143 elsif ($A_hex =~ /^a65959a6/ && $blck == 8) { 144 warn "key_unwrap: unexpected padding" unless $padding; 145 my $n = unpack("N", substr($A, 4, 4)); 146 my $z = length($rv) - $n; 147 my $tail = unpack("H*", substr($rv, -$z)); 148 croak "aes_key_unwrap: invalid data" unless $tail eq "00"x$z; 149 return substr($rv, 0, $n); 150 } 151 croak "aes_key_unwrap: unexpected data [$cipher/$A_hex]"; 152} 153 154# AES GCM KW - https://tools.ietf.org/html/rfc7518#section-4.7 155 156sub gcm_key_wrap { 157 my ($kek, $pt_data, $aad, $cipher, $iv) = @_; 158 $cipher = 'AES' unless defined $cipher; 159 $iv = random_bytes(12) unless defined $iv; # 96 bits REQUIRED by RFC7518 160 my ($ct_data, $tag) = gcm_encrypt_authenticate($cipher, $kek, $iv, $aad, $pt_data); 161 return ($ct_data, $tag, $iv); 162} 163 164sub gcm_key_unwrap { 165 my ($kek, $ct_data, $tag, $iv, $aad, $cipher) = @_; 166 $cipher ||= 'AES'; 167 my $pt_data = gcm_decrypt_verify($cipher, $kek, $iv, $aad, $ct_data, $tag); 168 return $pt_data; 169} 170 171# PBES2/PBKDF2 KW - https://tools.ietf.org/html/rfc7518#section-4.8 172 173sub pbes2_key_wrap { 174 my ($kek, $pt_data, $alg, $salt, $iter) = @_; 175 my ($hash_name, $len); 176 if ($alg =~ /^PBES2-HS(256|384|512)\+A(128|192|256)KW$/) { 177 $hash_name = "SHA$1"; 178 $len = $2/8; 179 my $aes_key = pbkdf2($kek, $alg."\x00".$salt, $iter, $hash_name, $len); 180 my $ct_data = aes_key_wrap($aes_key, $pt_data); 181 return $ct_data; 182 } 183 croak "pbes2_key_wrap: invalid alg '$alg'"; 184 return undef; 185} 186 187sub pbes2_key_unwrap { 188 my ($kek, $ct_data, $alg, $salt, $iter) = @_; 189 my ($hash_name, $len); 190 if ($alg =~ /^PBES2-HS(256|384|512)\+A(128|192|256)KW$/) { 191 $hash_name = "SHA$1"; 192 $len = $2/8; 193 my $aes_key = pbkdf2($kek, $alg."\x00".$salt, $iter, $hash_name, $len); 194 my $pt_data = aes_key_unwrap($aes_key, $ct_data); 195 return $pt_data; 196 } 197 croak "pbes2_key_unwrap: invalid alg '$alg'"; 198 return undef; 199} 200 201# RSA KW 202# https://tools.ietf.org/html/rfc7518#section-4.2 203# https://tools.ietf.org/html/rfc7518#section-4.3 204 205sub rsa_key_wrap { 206 my ($kek_public, $pt_data, $alg) = @_; 207 croak "rsa_key_wrap: no Crypt::PK::RSA" unless ref $kek_public eq 'Crypt::PK::RSA'; 208 my ($padding, $hash_name); 209 if ($alg eq 'RSA-OAEP') { ($padding, $hash_name) = ('oaep', 'SHA1') } 210 elsif ($alg eq 'RSA-OAEP-256') { ($padding, $hash_name) = ('oaep', 'SHA256') } 211 elsif ($alg eq 'RSA1_5') { $padding = 'v1.5' } 212 croak "rsa_key_wrap: invalid algorithm '$alg'" unless $padding; 213 my $ct_data = $kek_public->encrypt($pt_data, $padding, $hash_name); 214 return $ct_data; 215} 216 217sub rsa_key_unwrap { 218 my ($kek_private, $ct_data, $alg) = @_; 219 croak "rsa_key_unwrap: no Crypt::PK::RSA" unless ref $kek_private eq 'Crypt::PK::RSA'; 220 croak "rsa_key_unwrap: no private key" unless $kek_private->is_private; 221 my ($padding, $hash_name); 222 if ($alg eq 'RSA-OAEP') { ($padding, $hash_name) = ('oaep', 'SHA1') } 223 elsif ($alg eq 'RSA-OAEP-256') { ($padding, $hash_name) = ('oaep', 'SHA256') } 224 elsif ($alg eq 'RSA1_5') { $padding = 'v1.5' } 225 croak "rsa_key_unwrap: invalid algorithm '$alg'" unless $padding; 226 my $pt_data = $kek_private->decrypt($ct_data, $padding, $hash_name); 227 return $pt_data; 228} 229 230# ConcatKDF - http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Ar2.pdf 231# ECDH KW - https://tools.ietf.org/html/rfc7518#section-4.6 232 233sub _concat_kdf { 234 my ($hash_name, $key_size, $shared_secret, $algorithm, $apu, $apv) = @_; 235 $apu = '' unless defined $apu; 236 $apv = '' unless defined $apv; 237 my $hsize = Crypt::Digest->hashsize($hash_name); 238 my $count = int($key_size / $hsize); 239 $count++ if ($key_size % $hsize) > 0; 240 my $data = ''; 241 for my $i (1..$count) { 242 $data .= digest_data('SHA256', pack("N", 1) . 243 $shared_secret . 244 pack("N", length($algorithm)) . $algorithm . 245 pack("N", length($apu)) . $apu . 246 pack("N", length($apv)) . $apv . 247 pack("N", 8 *$key_size)); 248 } 249 return substr($data, 0, $key_size); 250} 251 252sub ecdh_key_wrap { 253 my ($kek_public, $enc, $apu, $apv) = @_; 254 croak "ecdh_key_wrap: no Crypt::PK::ECC" unless ref $kek_public eq 'Crypt::PK::ECC'; 255 my $encryption_key_size = 256; 256 if ($enc =~ /^A(128|192|256)CBC-HS/) { 257 $encryption_key_size = $1*2; 258 } 259 if ($enc =~ /^A(128|192|256)GCM/) { 260 $encryption_key_size = $1; 261 } 262 my $ephemeral = Crypt::PK::ECC->new()->generate_key($kek_public->curve2hash); 263 my $shared_secret = $ephemeral->shared_secret($kek_public); 264 my $ct_data = _concat_kdf('SHA256', $encryption_key_size/8, $shared_secret, $enc, $apu, $apv); 265 return ($ct_data, $ephemeral->export_key_jwk('public')); 266} 267 268sub ecdh_key_unwrap { 269 my ($kek_private, $enc, $epk, $apu, $apv) = @_; 270 croak "ecdh_key_unwrap: no Crypt::PK::ECC" unless ref $kek_private eq 'Crypt::PK::ECC'; 271 croak "ecdh_key_unwrap: no private key" unless $kek_private->is_private; 272 my $encryption_key_size = 256; 273 if ($enc =~ /^A(128|192|256)CBC-HS/) { 274 $encryption_key_size = $1*2; 275 } 276 if ($enc =~ /^A(128|192|256)GCM/) { 277 $encryption_key_size = $1; 278 } 279 my $ephemeral = ref($epk) eq 'Crypt::PK::ECC' ? $epk : Crypt::PK::ECC->new(ref $epk ? $epk : \$epk); 280 my $shared_secret = $kek_private->shared_secret($ephemeral); 281 my $pt_data = _concat_kdf('SHA256', $encryption_key_size/8, $shared_secret, $enc, $apu, $apv); 282 return $pt_data; 283} 284 285sub ecdhaes_key_wrap { 286 my ($kek_public, $pt_data, $alg, $apu, $apv) = @_; 287 croak "ecdhaes_key_wrap: no Crypt::PK::(ECC|X25519)" unless ref($kek_public) =~ /^Crypt::PK::(ECC|X25519)$/; 288 my $encryption_key_size = 256; 289 if ($alg =~ /^ECDH-ES\+A(128|192|256)KW$/) { 290 $encryption_key_size = $1; 291 } 292 my $ephemeral; 293 if (ref($kek_public) eq 'Crypt::PK::ECC') { 294 $ephemeral = Crypt::PK::ECC->new->generate_key($kek_public->curve2hash); 295 } 296 else { 297 $ephemeral = Crypt::PK::X25519->new->generate_key(); 298 } 299 my $shared_secret = $ephemeral->shared_secret($kek_public); 300 my $kek = _concat_kdf('SHA256', $encryption_key_size/8, $shared_secret, $alg, $apu, $apv); 301 return (aes_key_wrap($kek, $pt_data), $ephemeral->export_key_jwk('public')); 302} 303 304sub ecdhaes_key_unwrap { 305 my ($kek_private, $ct_data, $alg, $epk, $apu, $apv) = @_; 306 croak "ecdhaes_key_unwrap: no Crypt::PK::(ECC|X25519)" unless ref($kek_private) =~ /^Crypt::PK::(ECC|X25519)$/; 307 croak "ecdhaes_key_unwrap: no private key" unless $kek_private->is_private; 308 my $encryption_key_size = 256; 309 if ($alg =~ /^ECDH-ES\+A(128|192|256)KW$/) { 310 $encryption_key_size = $1; 311 } 312 my $ephemeral; 313 if (ref($kek_private) eq 'Crypt::PK::ECC') { 314 $ephemeral = ref($epk) eq 'Crypt::PK::ECC' ? $epk : Crypt::PK::ECC->new(ref $epk ? $epk : \$epk); 315 } 316 else { 317 $ephemeral = ref($epk) eq 'Crypt::PK::X25519' ? $epk : Crypt::PK::X25519->new(ref $epk ? $epk : \$epk); 318 } 319 my $shared_secret = $kek_private->shared_secret($ephemeral); 320 my $kek = _concat_kdf('SHA256', $encryption_key_size/8, $shared_secret, $alg, $apu, $apv); 321 my $pt_data = aes_key_unwrap($kek, $ct_data); 322 return $pt_data; 323} 324 3251; 326 327=pod 328 329=head1 NAME 330 331Crypt::KeyWrap - Key management/wrapping algorithms defined in RFC7518 (JWA) 332 333=head1 SYNOPSIS 334 335 # A192KW wrapping 336 use Crypt::KeyWrap qw(aes_key_wrap); 337 my $kek = pack("H*", "5840df6e29b02af1ab493b705bf16ea1ae8338f4dcc176a8"); # key encryption key 338 my $cek = pack("H*", "c37b7e6492584340bed12207808941155068f738"); # content encryption key 339 my $enc_cek = aes_key_wrap($kek, $pt_data); # encrypted content encryption key 340 341 # A192KW unwrapping 342 use Crypt::KeyWrap qw(aes_key_unwrap); 343 my $kek = pack("H*", "5840df6e29b02af1ab493b705bf16ea1ae8338f4dcc176a8"); 344 my $enc_cek = pack("H*", "138bdeaa9b8fa7fc61f97742e72248ee5ae6ae5360d1ae6a5f54f373fa543b6a"); 345 my $cek = aes_key_unwrap($kek, $pt_data); 346 347=head1 DESCRIPTION 348 349Implements key management algorithms defined in L<https://tools.ietf.org/html/rfc7518> 350 351BEWARE: experimental, interface of this module might change! 352 353Supported algorithms (all defined in RFC7518): 354 355 A128KW see: aes_key_wrap() + aes_key_unwrap() 356 A192KW see: aes_key_wrap() + aes_key_unwrap() 357 A256KW see: aes_key_wrap() + aes_key_unwrap() 358 A128GCMKW see: gcm_key_wrap() + gcm_key_unwrap() 359 A192GCMKW see: gcm_key_wrap() + gcm_key_unwrap() 360 A256GCMKW see: gcm_key_wrap() + gcm_key_unwrap() 361 PBES2-HS256+A128KW see: pbes2_key_wrap() + pbes2_key_unwrap() 362 PBES2-HS384+A192KW see: pbes2_key_wrap() + pbes2_key_unwrap() 363 PBES2-HS512+A256KW see: pbes2_key_wrap() + pbes2_key_unwrap() 364 RSA-OAEP see: rsa_key_wrap() + rsa_key_unwrap() 365 RSA-OAEP-256 see: rsa_key_wrap() + rsa_key_unwrap() 366 RSA1_5 see: rsa_key_wrap() + rsa_key_unwrap() 367 ECDH-ES+A128KW see: ecdhaes_key_wrap() + ecdhaes_key_unwrap() 368 ECDH-ES+A192KW see: ecdhaes_key_wrap() + ecdhaes_key_unwrap() 369 ECDH-ES+A256KW see: ecdhaes_key_wrap() + ecdhaes_key_unwrap() 370 ECDH-ES see: ecdh_key_wrap() + ecdh_key_unwrap() 371 372=head1 EXPORT 373 374Nothing is exported by default. 375 376You can export selected functions: 377 378 use Crypt::KeyWrap qw(aes_key_wrap gcm_key_wrap pbes2_key_wrap); 379 380Or all of them at once: 381 382 use Crypt::KeyWrap ':all'; 383 384=head1 FUNCTIONS 385 386=head2 aes_key_wrap 387 388AES key wrap algorithm as defined in L<https://tools.ietf.org/html/rfc7518#section-4.4> 389(implements algorithms C<A128KW>, C<A192KW>, C<A256KW>). 390 391Implementation follows L<https://tools.ietf.org/html/rfc5649> and L<https://tools.ietf.org/html/rfc3394>. 392 393The implementation is also compatible with L<http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-38F.pdf> 394(it supports AES based KW, KWP + TDEA/DES_EDE based TKW). 395 396AES Key Wrap algorithm. 397 398 $enc_cek = aes_key_wrap($kek, $cek); 399 # or 400 $enc_cek = aes_key_wrap($kek, $cek, $cipher, $padding, $inverse); 401 402 # params: 403 # $kek .. key encryption key (16bytes for AES128, 24 for AES192, 32 for AES256) 404 # $cek .. content encryption key 405 # optional params: 406 # $cipher .. 'AES' (default) or 'DES_EDE' 407 # $padding .. 1 (default) or 0 handle $cek padding (relevant for AES only) 408 # $inverse .. 0 (default) or 1 use cipher in inverse mode as defined by SP.800-38F 409 410Values C<$enc_cek>, C<$cek> and C<$kek> are binary octets. If you disable padding you have to make sure that 411C<$cek> length is multiply of 8 (for AES) or multiply of 4 (for DES_EDE); 412 413=head2 aes_key_unwrap 414 415AES key unwrap algorithm as defined in L<https://tools.ietf.org/html/rfc7518#section-4.4> 416(implements algorithms C<A128KW>, C<A192KW>, C<A256KW>). 417 418AES Key Unwrap algorithm. 419 420 $cek = aes_key_unwrap($kek, $enc_cek); 421 # or 422 $cek = aes_key_unwrap($kek, $enc_cek, $cipher, $padding, $inverse); 423 424 # params: 425 # $kek .. key encryption key (16bytes for AES128, 24 for AES192, 32 for AES256) 426 # $enc_cek .. encrypted content encryption key 427 # optional params: 428 # $cipher .. 'AES' (default) or 'DES_EDE' 429 # $padding .. 1 (default) or 0 - use $cek padding (relevant for AES only) 430 # $inverse .. 0 (default) or 1 - use cipher in inverse mode as defined by SP.800-38F 431 432Values C<$enc_cek>, C<$cek> and C<$kek> are binary octets. 433 434=head2 gcm_key_wrap 435 436AES GCM key wrap algorithm as defined in L<https://tools.ietf.org/html/rfc7518#section-4.7> 437(implements algorithms C<A128GCMKW>, C<A192GCMKW>, C<A256GCMKW>). 438 439 ($enc_cek, $tag, $iv) = gcm_key_wrap($kek, $cek); 440 #or 441 ($enc_cek, $tag, $iv) = gcm_key_wrap($kek, $cek, $aad); 442 #or 443 ($enc_cek, $tag, $iv) = gcm_key_wrap($kek, $cek, $aad, $cipher, $iv); 444 445 # params: 446 # $kek .. key encryption key (16bytes for AES128, 24 for AES192, 32 for AES256) 447 # $cek .. content encryption key 448 # optional params: 449 # $aad .. additional authenticated data, DEFAULT is '' (empty string) 450 # $cipher .. cipher to be used by GCM, DEFAULT is 'AES' 451 # $iv .. initialization vector (if not defined a random IV is generated) 452 453Values C<$enc_cek>, C<$cek>, C<$aad>, C<$iv>, C<$tag> and C<$kek> are binary octets. 454 455=head2 gcm_key_unwrap 456 457AES GCM key unwrap algorithm as defined in L<https://tools.ietf.org/html/rfc7518#section-4.7> 458(implements algorithms C<A128GCMKW>, C<A192GCMKW>, C<A256GCMKW>). 459 460 $cek = gcm_key_unwrap($kek, $enc_cek, $tag, $iv); 461 # or 462 $cek = gcm_key_unwrap($kek, $enc_cek, $tag, $iv, $aad); 463 # or 464 $cek = gcm_key_unwrap($kek, $enc_cek, $tag, $iv, $aad, $cipher); 465 466 # params: 467 # $kek .. key encryption key (16bytes for AES128, 24 for AES192, 32 for AES256) 468 # $enc_cek .. encrypted content encryption key 469 # $tag .. GCM's tag 470 # $iv .. initialization vector 471 # optional params: 472 # $aad .. additional authenticated data, DEFAULT is '' (empty string) 473 # $cipher .. cipher to be used by GCM, DEFAULT is 'AES' 474 475Values C<$enc_cek>, C<$cek>, C<$aad>, C<$iv>, C<$tag> and C<$kek> are binary octets. 476 477=head2 pbes2_key_wrap 478 479PBES2 key wrap algorithm as defined in L<https://tools.ietf.org/html/rfc7518#section-4.8> 480(implements algorithms C<PBES2-HS256+A128KW>, C<PBES2-HS384+A192KW>, C<PBES2-HS512+A256KW>). 481 482 $enc_cek = pbes2_key_wrap($kek, $cek, $alg, $salt, $iter); 483 484 # params: 485 # $kek .. key encryption key (arbitrary length) 486 # $cek .. content encryption key 487 # $alg .. algorithm name e.g. 'PBES2-HS256+A128KW' (see rfc7518) 488 # $salt .. pbkdf2 salt 489 # $iter .. pbkdf2 iteration count 490 491Values C<$enc_cek>, C<$cek>, C<$salt> and C<$kek> are binary octets. 492 493=head2 pbes2_key_unwrap 494 495PBES2 key unwrap algorithm as defined in L<https://tools.ietf.org/html/rfc7518#section-4.8> 496(implements algorithms C<PBES2-HS256+A128KW>, C<PBES2-HS384+A192KW>, C<PBES2-HS512+A256KW>). 497 498 $cek = pbes2_key_unwrap($kek, $enc_cek, $alg, $salt, $iter); 499 500 # params: 501 # $kek .. key encryption key (arbitrary length) 502 # $enc_cek .. encrypted content encryption key 503 # $alg .. algorithm name e.g. 'PBES2-HS256+A128KW' (see rfc7518) 504 # $salt .. pbkdf2 salt 505 # $iter .. pbkdf2 iteration count 506 507Values C<$enc_cek>, C<$cek>, C<$salt> and C<$kek> are binary octets. 508 509=head2 rsa_key_wrap 510 511PBES2 key wrap algorithm as defined in L<https://tools.ietf.org/html/rfc7518#section-4.2> and 512L<https://tools.ietf.org/html/rfc7518#section-4.3> (implements algorithms C<RSA1_5>, C<RSA-OAEP-256>, C<RSA-OAEP>). 513 514 $enc_cek = rsa_key_wrap($kek, $cek, $alg); 515 516 # params: 517 # $kek .. RSA public key - Crypt::PK::RSA instance 518 # $cek .. content encryption key 519 # $alg .. algorithm name e.g. 'RSA-OAEP' (see rfc7518) 520 521Values C<$enc_cek> and C<$cek> are binary octets. 522 523=head2 rsa_key_unwrap 524 525PBES2 key wrap algorithm as defined in L<https://tools.ietf.org/html/rfc7518#section-4.2> and 526L<https://tools.ietf.org/html/rfc7518#section-4.3> (implements algorithms C<RSA1_5>, C<RSA-OAEP-256>, C<RSA-OAEP>). 527 528 $cek = rsa_key_unwrap($kek, $enc_cek, $alg); 529 530 # params: 531 # $kek .. RSA private key - Crypt::PK::RSA instance 532 # $enc_cek .. encrypted content encryption key 533 # $alg .. algorithm name e.g. 'RSA-OAEP' (see rfc7518) 534 535Values C<$enc_cek> and C<$cek> are binary octets. 536 537=head2 ecdhaes_key_wrap 538 539ECDH+AESKW key agreement/wrap algorithm as defined in L<https://tools.ietf.org/html/rfc7518#section-4.6> 540(implements algorithms C<ECDH-ES+A128KW>, C<ECDH-ES+A192KW>, C<ECDH-ES+A256KW>). 541 542 ($enc_cek, $epk) = ecdhaes_key_wrap($kek, $cek, $alg, $apu, $apv); 543 544 # params: 545 # $kek .. ECC public key - Crypt::PK::ECC|X25519 instance 546 # $cek .. content encryption key 547 # $alg .. algorithm name e.g. 'ECDH-ES+A256KW' (see rfc7518) 548 # optional params: 549 # $apu .. Agreement PartyUInfo Header Parameter 550 # $apv .. Agreement PartyVInfo Header Parameter 551 552Values C<$enc_cek> and C<$cek> are binary octets. 553 554=head2 ecdhaes_key_unwrap 555 556ECDH+AESKW key agreement/unwrap algorithm as defined in L<https://tools.ietf.org/html/rfc7518#section-4.6> 557(implements algorithms C<ECDH-ES+A128KW>, C<ECDH-ES+A192KW>, C<ECDH-ES+A256KW>). 558 559 $cek = ecdhaes_key_unwrap($kek, $enc_cek, $alg, $epk, $apu, $apv); 560 561 # params: 562 # $kek .. ECC private key - Crypt::PK::ECC|X25519 instance 563 # $enc_cek .. encrypted content encryption key 564 # $alg .. algorithm name e.g. 'ECDH-ES+A256KW' (see rfc7518) 565 # $epk .. ephemeral ECC public key (JWK/JSON or Crypt::PK::ECC|X25519) 566 # optional params: 567 # $apu .. Agreement PartyUInfo Header Parameter 568 # $apv .. Agreement PartyVInfo Header Parameter 569 570Values C<$enc_cek> and C<$cek> are binary octets. 571 572=head2 ecdh_key_wrap 573 574ECDH (Ephememeral Static) key agreement/wrap algorithm as defined in L<https://tools.ietf.org/html/rfc7518#section-4.6> 575(implements algorithm C<ECDH-ES>). 576 577 ($cek, $epk) = ecdh_key_wrap($kek, $enc, $apu, $apv); 578 579 # params: 580 # $kek .. ECC public key - Crypt::PK::ECC|X25519 instance 581 # $enc .. encryption algorithm name e.g. 'A256GCM' (see rfc7518) 582 # optional params: 583 # $apu .. Agreement PartyUInfo Header Parameter 584 # $apv .. Agreement PartyVInfo Header Parameter 585 586Value C<$cek> - binary octets, C<$epk> JWK/JSON string with ephemeral ECC public key. 587 588=head2 ecdh_key_unwrap 589 590ECDH (Ephememeral Static) key agreement/unwrap algorithm as defined in L<https://tools.ietf.org/html/rfc7518#section-4.6> 591(implements algorithm C<ECDH-ES>). 592 593 $cek = ecdh_key_unwrap($kek, $enc, $epk, $apu, $apv); 594 595 # params: 596 # $kek .. ECC private key - Crypt::PK::ECC|X25519 instance 597 # $enc .. encryption algorithm name e.g. 'A256GCM' (see rfc7518) 598 # $epk .. ephemeral ECC public key (JWK/JSON or Crypt::PK::ECC|X25519) 599 # optional params: 600 # $apu .. Agreement PartyUInfo Header Parameter 601 # $apv .. Agreement PartyVInfo Header Parameter 602 603Value C<$cek> - binary octets. 604 605=head1 SEE ALSO 606 607L<Crypt::Cipher::AES>, L<Crypt::AuthEnc::GCM>, L<Crypt::PK::RSA>, L<Crypt::KeyDerivation> 608 609=head1 LICENSE 610 611This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. 612 613=head1 COPYRIGHT 614 615Copyright (c) 2015-2021 DCIT, a.s. L<https://www.dcit.cz> / Karel Miko 616