.\" -*- mode: troff; coding: utf-8 -*- .\" Automatically generated by Pod::Man v6.0.2 (Pod::Simple 3.45) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" \*(C` and \*(C' are quotes in nroff, nothing in troff, for use with C<>. .ie n \{\ . ds C` "" . ds C' "" 'br\} .el\{\ . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{\ . if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" .\" Required to disable full justification in groff 1.23.0. .if n .ds AD l .\" ======================================================================== .\" .IX Title "Crypt::PK::X448 3" .TH Crypt::PK::X448 3 2026-08-10 "perl v5.42.2" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH NAME Crypt::PK::X448 \- Asymmetric cryptography based on X448 .SH SYNOPSIS .IX Header "SYNOPSIS" .Vb 1 \& use Crypt::PK::X448; \& \& my $alice = Crypt::PK::X448\->new\->generate_key; \& my $bob = Crypt::PK::X448\->new\->generate_key; \& my $alice_secret = $alice\->shared_secret($bob); \& my $bob_secret = $bob\->shared_secret($alice); \& die "ERROR" unless $alice_secret eq $bob_secret; \& \& my $pk = Crypt::PK::X448\->new; \& $pk\->import_key_raw( \& pack("H*", "cf807ab0fc3efa03108469f29e499db2eefefeb12544d8d4e711f187385aaf31b4f38c8f84a3dd9e43da309fd410c3816a50e644b5500c05"), \& "public", \& ); \& \& my $sk = Crypt::PK::X448\->new; \& $sk\->import_key_raw( \& pack("H*", "10d418b111401956abc5a92c2fbb8406d1d646ba930fdefa2108efe68f2000973755aa952be018f640947c05135fbf9925ebd4da828d86ec"), \& "private", \& ); \& \& my $generated = Crypt::PK::X448\->new\->generate_key; \& my $private_der = $generated\->export_key_der(\*(Aqprivate\*(Aq); \& my $public_pem = $generated\->export_key_pem(\*(Aqpublic\*(Aq); \& my $private_jwk = $generated\->export_key_jwk(\*(Aqprivate\*(Aq); .Ve .SH DESCRIPTION .IX Header "DESCRIPTION" \&\fISince: CryptX\-0.089\fR .SH METHODS .IX Header "METHODS" .SS new .IX Subsection "new" .Vb 2 \& my $source = Crypt::PK::X448\->new(); \& $source\->generate_key; \& \& my $public_der = $source\->export_key_der(\*(Aqpublic\*(Aq); \& my $pub = Crypt::PK::X448\->new(\e$public_der); \& \& my $private_pem = $source\->export_key_pem(\*(Aqprivate\*(Aq, \*(Aqsecret\*(Aq, \*(AqAES\-256\-CBC\*(Aq); \& my $priv = Crypt::PK::X448\->new(\e$private_pem, \*(Aqsecret\*(Aq); .Ve .PP Passing \f(CW$filename\fR or \f(CW\*(C`\e$buffer\*(C'\fR to \f(CW\*(C`new\*(C'\fR is equivalent: both forms immediately import the key material into the new object. .SS generate_key .IX Subsection "generate_key" Returns the object itself (for chaining). .PP .Vb 1 \& $pk\->generate_key; .Ve .SS import_key .IX Subsection "import_key" Loads X448 private or public keys from DER, PEM, PKCS#8, SubjectPublicKeyInfo, or JWK. .PP .Vb 2 \& my $source = Crypt::PK::X448\->new(); \& $source\->generate_key; \& \& my $public_der = $source\->export_key_der(\*(Aqpublic\*(Aq); \& my $pub = Crypt::PK::X448\->new(); \& $pub\->import_key(\e$public_der); \& my $private_pem = $source\->export_key_pem(\*(Aqprivate\*(Aq, \*(Aqsecret\*(Aq, \*(AqAES\-256\-CBC\*(Aq); \& my $priv = Crypt::PK::X448\->new(); \& $priv\->import_key(\e$private_pem, \*(Aqsecret\*(Aq); \& $pk\->import_key({ \& curve => "x448", \& pub => "CF807AB0FC3EFA03108469F29E499DB2EEFEFEB12544D8D4E711F187385AAF31B4F38C8F84A3DD9E43DA309FD410C3816A50E644B5500C05", \& priv => "10D418B111401956ABC5A92C2FBB8406D1D646BA930FDEFA2108EFE68F2000973755AA952BE018F640947C05135FBF9925EBD4DA828D86EC", \& }); \& $pk\->import_key({ \& kty => "OKP", \& crv => "X448", \& d => "ENQYsRFAGVarxaksL7uEBtHWRrqTD976IQjv5o8gAJc3VaqVK\-AY9kCUfAUTX7\-ZJevU2oKNhuw", \& x => "z4B6sPw\-\-gMQhGnynkmdsu7\-_rElRNjU5xHxhzharzG084yPhKPdnkPaMJ_UEMOBalDmRLVQDAU", \& }); .Ve .PP The same method also accepts filenames instead of buffers. .SS import_key_raw .IX Subsection "import_key_raw" Import raw public/private key bytes. .PP .Vb 2 \& $pk\->import_key_raw($key, \*(Aqpublic\*(Aq); \& $pk\->import_key_raw($key, \*(Aqprivate\*(Aq); .Ve .PP The raw key must be exactly 56 bytes long. .SS export_key_der .IX Subsection "export_key_der" Returns the key as a binary DER\-encoded string. .PP .Vb 2 \& my $der = $pk\->export_key_der(\*(Aqprivate\*(Aq); \& my $der = $pk\->export_key_der(\*(Aqpublic\*(Aq); .Ve .SS export_key_pem .IX Subsection "export_key_pem" Returns the key as a PEM\-encoded string (ASCII). .PP .Vb 3 \& my $pem = $pk\->export_key_pem(\*(Aqprivate\*(Aq); \& my $pem = $pk\->export_key_pem(\*(Aqpublic\*(Aq); \& my $pem = $pk\->export_key_pem(\*(Aqprivate\*(Aq, $password, \*(AqAES\-256\-CBC\*(Aq); .Ve .SS export_key_jwk .IX Subsection "export_key_jwk" Returns a JSON string, or a hashref if the optional second argument is true. .PP .Vb 2 \& my $json = $pk\->export_key_jwk(\*(Aqprivate\*(Aq); \& my $hash = $pk\->export_key_jwk(\*(Aqpublic\*(Aq, 1); .Ve .SS export_key_raw .IX Subsection "export_key_raw" Returns the raw key as a binary string. .PP .Vb 2 \& my $raw = $pk\->export_key_raw(\*(Aqprivate\*(Aq); \& my $raw = $pk\->export_key_raw(\*(Aqpublic\*(Aq); .Ve .SS shared_secret .IX Subsection "shared_secret" Returns the shared secret as a binary string (raw bytes). .PP .Vb 1 \& my $shared_secret = $private_key\->shared_secret($public_key); .Ve .SS is_private .IX Subsection "is_private" .Vb 1 \& my $rv = $pk\->is_private; .Ve .SS key2hash .IX Subsection "key2hash" Returns a hashref with the key components, or \f(CW\*(C`undef\*(C'\fR if no key is loaded. .PP .Vb 1 \& my $hash = $pk\->key2hash; .Ve .PP Returns a hash like: .PP .Vb 5 \& { \& curve => "x448", \& pub => "CF807AB0FC3EFA03108469F29E499DB2EEFEFEB12544D8D4E711F187385AAF31B4F38C8F84A3DD9E43DA309FD410C3816A50E644B5500C05", \& priv => "10D418B111401956ABC5A92C2FBB8406D1D646BA930FDEFA2108EFE68F2000973755AA952BE018F640947C05135FBF9925EBD4DA828D86EC", \& } .Ve .SH "OpenSSL interoperability" .IX Header "OpenSSL interoperability" .Vb 3 \& # Generate a key with OpenSSL \& # openssl genpkey \-algorithm x448 \-out x448_priv.pem \& # openssl pkey \-in x448_priv.pem \-pubout \-out x448_pub.pem \& \& # Load the OpenSSL\-generated key in CryptX \& use Crypt::PK::X448; \& my $alice = Crypt::PK::X448\->new("x448_priv.pem"); \& my $bob_pub = Crypt::PK::X448\->new("bob_x448_pub.pem"); \& \& # Derive shared secret \& my $shared_secret = $alice\->shared_secret($bob_pub); \& \& # Export CryptX key for OpenSSL \& my $pem = $alice\->export_key_pem(\*(Aqprivate\*(Aq); \& # then: openssl pkey \-in priv.pem \-text \-noout .Ve .SH "SEE ALSO" .IX Header "SEE ALSO" .IP \(bu 4 .IP \(bu 4 Crypt::PK::X25519