NAME
Crypt::PK::DSA - Public key cryptography based on DSA
SYNOPSIS
### OO interfacemy $message = 'hello world';my $signer = Crypt::PK::DSA->new();$signer->generate_key(30, 256);my $signature = $signer->sign_message($message, 'SHA256');my $public_der = $signer->export_key_der('public');my $verifier = Crypt::PK::DSA->new(\$public_der);$verifier->verify_message($signature, $message, 'SHA256') or die "ERROR";my $ciphertext = $verifier->encrypt("secret message");my $plaintext = $signer->decrypt($ciphertext);my $private_der = $signer->export_key_der('private');my $private_pem = $signer->export_key_pem('private');my $public_pem = $verifier->export_key_pem('public');
DESCRIPTION
DSA is primarily a digital signature scheme. In this module, signing and verification are the most common operations and therefore the primary examples.
Legacy function-style wrappers still exist in code for backwards compatibility, but they are intentionally undocumented.
METHODS
new
my $source = Crypt::PK::DSA->new();$source->generate_key(20, 128);my $public_der = $source->export_key_der('public');my $pub = Crypt::PK::DSA->new(\$public_der);my $private_pem = $source->export_key_pem('private', 'secret', 'AES-256-CBC');my $priv = Crypt::PK::DSA->new(\$private_pem, 'secret');
Passing $filename or "\$buffer" to "new" is equivalent: both forms immediately import the key material into the new object.
generate_key
Uses the bundled "chacha20" PRNG via libtomcrypt's "rng_make_prng". Returns the object itself (for chaining).
$pk->generate_key($group_size, $modulus_size);# $group_size ... [integer] size of the subgroup (q) in bytes; must satisfy: 15 < $group_size < 1024# $modulus_size .. [integer] size of the prime (p) in bytes; must satisfy: ($modulus_size - $group_size) < 512# $modulus_size must be >= $group_size## The two-integer form uses Perl's usual numeric-to-integer coercion before# the XS call. Callers should therefore pass exact integers; values like# C<10.9> or C<"1e1"> will be coerced according to Perl's integer conversion.### Common parameter pairs (group_size, modulus_size) => security level:# generate_key(20, 128) => 80-bit security (1024-bit p, 160-bit q)# generate_key(30, 256) => 120-bit security (2048-bit p, 240-bit q)# generate_key(32, 256) => 128-bit security (2048-bit p, 256-bit q)# generate_key(35, 384) => ~140-bit security (3072-bit p, 280-bit q)# 140 bits => generate_key(35, 384)# 160 bits => generate_key(40, 512)### Sizes according section 4.2 of FIPS 186-4# (L and N are the bit lengths of p and q respectively)# L = 1024, N = 160 => generate_key(20, 128)# L = 2048, N = 224 => generate_key(28, 256)# L = 2048, N = 256 => generate_key(32, 256)# L = 3072, N = 256 => generate_key(32, 384)$pk->generate_key($param_hash)# $param_hash is { p => $p, q => $q, g => $g }# where $p, $q, $g are hex strings$pk->generate_key(\$dsa_param)# $dsa_param is the content of DER or PEM file with DSA params# e.g. openssl dsaparam 2048
import_key
Loads private or public key in DER or PEM format.
my $source = Crypt::PK::DSA->new();$source->generate_key(20, 128);my $public_der = $source->export_key_der('public');my $pub = Crypt::PK::DSA->new();$pub->import_key(\$public_der);my $private_pem = $source->export_key_pem('private', 'secret', 'AES-256-CBC');my $priv = Crypt::PK::DSA->new();$priv->import_key(\$private_pem, 'secret');
The same method also accepts filenames instead of buffers.
Loading private or public keys from a Perl HASH:
$pk->import_key($hashref);# where $hashref is a key exported via key2hash$pk->import_key({p => "AAF839A764E04D80824B79FA1F0496C093...", #prime modulusq => "D05C4CB45F29D353442F1FEC43A6BE2BE8...", #prime divisorg => "847E8896D12C9BF18FE283AE7AD58ED7F3...", #generator of a subgroup of order q in GF(p)x => "6C801901AC74E2DC714D75A9F6969483CF...", #private key, random 0 < x < qy => "8F7604D77FA62C7539562458A63C7611B7...", #public key, where y = g^x mod p});
Supported key formats:
- •
-
DSA public keys
-----BEGIN PUBLIC KEY-----MIIBtjCCASsGByqGSM44BAEwggEeAoGBAJKyu+puNMGLpGIhbD1IatnwlI79ePr4YHe2KBhRkheKxWUZRpN1Vd/+usS2IHSJ9op5cSWETiP05d7PMtJaitklw7jhudq3GxNvV/GRdCQm3H6d76FHP88dms4vcDYc6ry6wKERGfNEtZ+4BAKrMZK+gDYsF4AwU6WVR969kYZhAhUA6w25FgSRmJ8W4XkvC60n8Wv3DpMCgYA4ZFE+3tLOM24PZj9ZrxuqUzZZdR+kIzrsIYpWN9ustbmdKLKwsqIaUIxc5zxHEhbAjAIf8toPD+VEQIpY7vgJgDhXuPq45BgN19iLTzOJwIhAFXPZvnAdIo9D/AnMw688gT6g6U8QCZwX2XYgICiVcriYVNcjVKHSFY/X0Oi7CgOBhAACgYB4ZTn4OYT/pjUd6tNhGPtOS3CE1oaj5ScbetXg4ZDpceEyQi8VG+/ZTbs8var8X77JdEdeQA686cAxpOaVgW8V4odvcmfABfueiGnPXjqGfppiHAyL1Ngyd+EsXKmKVXZYAVFVI0WuJKiZBSVURU7+ByxOfpGafZhibr0SggWixQ==-----END PUBLIC KEY-----
- •
-
DSA private keys
-----BEGIN DSA PRIVATE KEY-----MIIBuwIBAAKBgQCSsrvqbjTBi6RiIWw9SGrZ8JSO/Xj6+GB3tigYUZIXisVlGUaTdVXf/rrEtiB0ifaKeXElhE4j9OXezzLSWorZJcO44bnatxsTb1fxkXQkJtx+ne+hRz/PHZrOL3A2HOq8usChERnzRLWfuAQCqzGSvoA2LBeAMFOllUfevZGGYQIVAOsNuRYEkZifFuF5LwutJ/Fr9w6TAoGAOGRRPt7SzjNuD2Y/Wa8bqlM2WXUfpCM67CGKVjfbrLW5nSiysLKiGlCMXOc8RxIWwIwCH/LaDw/lRECKWO74CYA4V7j6uOQYDdfYi08zicCIQBVz2b5wHSKPQ/wJzMOvPIE+oOlPEAmcF9l2ICAolXK4mFTXI1Sh0hWP19DouwoCgYB4ZTn4OYT/pjUd6tNhGPtOS3CE1oaj5ScbetXg4ZDpceEyQi8VG+/ZTbs8var8X77JdEdeQA686cAxpOaVgW8V4odvcmfABfueiGnPXjqGfppiHAyL1Ngyd+EsXKmKVXZYAVFVI0WuJKiZBSVURU7+ByxOfpGafZhibr0SggWixQIVAL7Sia038bvANjjL9Sitk8slrM6P-----END DSA PRIVATE KEY-----
- •
-
DSA private keys in password protected PEM format:
-----BEGIN DSA PRIVATE KEY-----Proc-Type: 4,ENCRYPTEDDEK-Info: DES-CBC,227ADC3AA0299491UISxBYAxPQMl2eK9LMAeHsssF6IxO+4G2ta2Jn8VE+boJrrH3iSTKeMXGjGaXl0zDwcLGV+KMR70y+cxtTb34rFy+uSpBy10dOQJhxALDbe1XfCDQIUfaXRfMNA3um2IJdZixUD/zcxBOUzao+MCr0V9XlJDgqBhJ5EEr53XHH07Eo5fhiBfbbR9NzdUPFrQp2ASyZtFh7RXoIBUCQgg21oeLddcNWV7gd/Y46kghO9s0JbJ8C+IsuWEPRSq502htSoDN6B0sxbVvOUICLLbQaxt7yduTAhRxVIJZ1PWATTVD7CZBVz9uIDZ7LOv+er21q3vkwb8E9spPsA240+BnfD571XEop4jrawxC0VKQZ+3cPVLc6jhIsxvzzFQUt67g66v8GUgt7KF3KhVV7qEtntybQWDWb+K/uTIH9Ra8nP820d3Rnl61pPXDPlluteTWSLOvEMN2zRmkaxQNv/tLdT0SYpQtdjw74G3A6T7+KnvinKrjtp1a/AXkCF9hNExDGbxOYo1UOmk8qdxWCrab34nO+Q8oQc9wjXHG+ZtRYIMoGMKREK8DeL4H1RPNkMfrwXWk8scd8QFmJAb8De1VQ==-----END DSA PRIVATE KEY-----
- •
-
SSH public DSA keys
ssh-dss AAAAB3NzaC1kc3MAAACBAKU8/avmk...4XOwuEssAVhmwA==
- •
-
SSH public DSA keys (RFC-4716 format)
---- BEGIN SSH2 PUBLIC KEY ----Comment: "1024-bit DSA, converted from OpenSSH"AAAAB3NzaC1kc3MAAACBAKU8/avmkFeGnSqwYG7dZnQlG+01QNaxu3F5v0NcL/SRUW7IdpUq8t14siK0mA6yjphLhOf5t8gugTEVBllP86ANSbFigH7WN3v6ydJWqm60pNhNHN//50cnNtIsXbxeq3VtsI64pkH1OJqeZDHLmu73k4T0EKOzsylSfF/wtVBJAAAAFQChpubLHViwPB+jSvUb8e4THS7PBQAAAIAJD1PMCiTCQa1xyD/NCWOajCufTOIzKAhm6l+nlBVPiKI+262XpYt127Ke4mPL8XJBizoTjSQN08uHMg/8L6W/cdO2aZ+mhkBnS1xAm83DAwqLrDraR1w/4QRFxr5Vbyy8qnejrPjTJobBN1BGsv84wHkjmoCn6pFIfkGYeATlJgAAAIAHYPU1zMVBTDWru7SNC4G2UyWGWYYLjLytBVHfQmBa51CmqrSs2kCfGLGA1ynfYENsxcJq9nsXrb4i17H5BHJFkH0g7BUDpeBeLr8gsK3WgfqWwtZsDkltObw9chUD/siK6q/dk/fSIB2Ho0inev7k68Z5ZkNI4XOwuEssAVhmwA==---- END SSH2 PUBLIC KEY ----
export_key_der
Returns the key as a binary DER-encoded string.
my $private_der = $pk->export_key_der('private');#ormy $public_der = $pk->export_key_der('public');
export_key_pem
Returns the key as a PEM-encoded string (ASCII).
my $private_pem = $pk->export_key_pem('private');#ormy $public_pem = $pk->export_key_pem('public');#ormy $public_pem = $pk->export_key_pem('public_x509');
With parameter 'public' uses header and footer lines:
-----BEGIN DSA PUBLIC KEY-----------END DSA PUBLIC KEY------
With parameter 'public_x509' uses header and footer lines:
-----BEGIN PUBLIC KEY-----------END PUBLIC KEY------
Support for password protected PEM keys
my $private_pem = $pk->export_key_pem('private', $password);#ormy $private_pem = $pk->export_key_pem('private', $password, $cipher);# supported ciphers: 'DES-CBC'# 'DES-EDE3-CBC'# 'SEED-CBC'# 'CAMELLIA-128-CBC'# 'CAMELLIA-192-CBC'# 'CAMELLIA-256-CBC'# 'AES-128-CBC'# 'AES-192-CBC'# 'AES-256-CBC' (DEFAULT)
encrypt
Returns the ciphertext as a binary string.
DSA is usually used for signatures. This helper is available because the underlying library exposes a DSA-based encryption primitive.
my $pk = Crypt::PK::DSA->new($pub_key_filename);my $ct = $pk->encrypt($message);#ormy $ct = $pk->encrypt($message, $hash_name);# $hash_name .. [string] 'SHA1' (DEFAULT), 'SHA256' or any other hash supported by Crypt::Digest
decrypt
Returns the plaintext as a binary string.
my $pk = Crypt::PK::DSA->new($priv_key_filename);my $pt = $pk->decrypt($ciphertext);
sign_message
Returns the signature as a binary string.
my $pk = Crypt::PK::DSA->new($priv_key_filename);my $signature = $pk->sign_message($message);#ormy $signature = $pk->sign_message($message, $hash_name);# $hash_name .. [string] 'SHA1' (DEFAULT, INSECURE), 'SHA256' or any other hash supported by Crypt::Digest
BEWARE: The $hash_name default is 'SHA1' only for backward compatibility. SHA-1 is vulnerable to practical collision attacks and is not safe for signing messages whose content may be influenced by an attacker. Always pass an explicit hash name such as 'SHA256'. The same applies to "verify_message".
verify_message
Returns 1 if the signature is valid, 0 otherwise.
my $pk = Crypt::PK::DSA->new($pub_key_filename);my $valid = $pk->verify_message($signature, $message);#ormy $valid = $pk->verify_message($signature, $message, $hash_name);# $hash_name .. [string] 'SHA1' (DEFAULT, INSECURE), 'SHA256' or any other hash supported by Crypt::Digest
sign_hash
Returns the signature as a binary string.
my $pk = Crypt::PK::DSA->new($priv_key_filename);my $signature = $pk->sign_hash($message_hash);
verify_hash
Returns 1 if the signature is valid, 0 otherwise.
my $pk = Crypt::PK::DSA->new($pub_key_filename);my $valid = $pk->verify_hash($signature, $message_hash);
is_private
my $rv = $pk->is_private;# 1 .. private key loaded# 0 .. public key loaded# undef .. no key loaded
size
my $size = $pk->size;# returns key size (length of the prime p) in bytes or undef if key not loaded
size_q
my $size = $pk->size_q;# returns length of the prime q in bytes or undef if key not loaded
key2hash
Returns a hashref with the key components, or "undef" if no key is loaded.
my $hash = $pk->key2hash;# returns hash like this (or undef if no key loaded):{type => 1, # integer: 1 .. private, 0 .. publicsize => 256, # integer: key size in bytes# all the rest are hex stringsp => "AAF839A764E04D80824B79FA1F0496C093...", #prime modulusq => "D05C4CB45F29D353442F1FEC43A6BE2BE8...", #prime divisorg => "847E8896D12C9BF18FE283AE7AD58ED7F3...", #generator of a subgroup of order q in GF(p)x => "6C801901AC74E2DC714D75A9F6969483CF...", #private key, random 0 < x < qy => "8F7604D77FA62C7539562458A63C7611B7...", #public key, where y = g^x mod p}
OpenSSL interoperability
### let's have:# DSA private key in PEM format - dsakey.priv.pem# DSA public key in PEM format - dsakey.pub.pem# data file to be signed - input.data
Sign by OpenSSL, verify by Crypt::PK::DSA
Create signature (from commandline):
openssl dgst -sha256 -sign dsakey.priv.pem -out input.sha256-dsa.sig input.data
Verify signature (Perl code):
use Crypt::PK::DSA;use Crypt::Digest 'digest_file';use Crypt::Misc 'read_rawfile';my $pkdsa = Crypt::PK::DSA->new("dsakey.pub.pem");my $signature = read_rawfile("input.sha256-dsa.sig");my $valid = $pkdsa->verify_hash($signature, digest_file("SHA256", "input.data"));print $valid ? "SUCCESS" : "FAILURE";
Sign by Crypt::PK::DSA, verify by OpenSSL
Create signature (Perl code):
use Crypt::PK::DSA;use Crypt::Digest 'digest_file';use Crypt::Misc 'write_rawfile';my $pkdsa = Crypt::PK::DSA->new("dsakey.priv.pem");my $signature = $pkdsa->sign_hash(digest_file("SHA256", "input.data"));write_rawfile("input.sha256-dsa.sig", $signature);
Verify signature (from commandline):
openssl dgst -sha256 -verify dsakey.pub.pem -signature input.sha256-dsa.sig input.data
Keys generated by Crypt::PK::DSA
Generate keys (Perl code):
use Crypt::PK::DSA;use Crypt::Misc 'write_rawfile';my $pkdsa = Crypt::PK::DSA->new;$pkdsa->generate_key(20, 128);write_rawfile("dsakey.pub.der", $pkdsa->export_key_der('public'));write_rawfile("dsakey.priv.der", $pkdsa->export_key_der('private'));write_rawfile("dsakey.pub.pem", $pkdsa->export_key_pem('public_x509'));write_rawfile("dsakey.priv.pem", $pkdsa->export_key_pem('private'));write_rawfile("dsakey-passwd.priv.pem", $pkdsa->export_key_pem('private', 'secret'));
Use keys by OpenSSL:
openssl dsa -in dsakey.priv.der -text -inform deropenssl dsa -in dsakey.priv.pem -textopenssl dsa -in dsakey-passwd.priv.pem -text -inform pem -passin pass:secretopenssl dsa -in dsakey.pub.der -pubin -text -inform deropenssl dsa -in dsakey.pub.pem -pubin -text
Keys generated by OpenSSL
Generate keys:
openssl dsaparam -genkey -out dsakey.priv.pem 1024openssl dsa -in dsakey.priv.pem -out dsakey.priv.der -outform deropenssl dsa -in dsakey.priv.pem -out dsakey.pub.pem -puboutopenssl dsa -in dsakey.priv.pem -out dsakey.pub.der -outform der -puboutopenssl dsa -in dsakey.priv.pem -passout pass:secret -des3 -out dsakey-passwd.priv.pem
Load keys (Perl code):
use Crypt::PK::DSA;my $pkdsa = Crypt::PK::DSA->new;$pkdsa->import_key("dsakey.pub.der");$pkdsa->import_key("dsakey.priv.der");$pkdsa->import_key("dsakey.pub.pem");$pkdsa->import_key("dsakey.priv.pem");$pkdsa->import_key("dsakey-passwd.priv.pem", "secret");
SEE ALSO
- •
-
<https://en.wikipedia.org/wiki/Digital_Signature_Algorithm>