Skip Menu |

This queue is for tickets about the Crypt-Sodium CPAN distribution.

Report information
The Basics
Id: 102894
Status: resolved
Worked: 2 hours (120 min)
Priority: 0/
Queue: Crypt-Sodium

People
Owner: mike [...] mg2.org
Requestors: tlinden [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: Wishlist
Broken in: 0.06
Fixed in: (no value)



Subject: [PATCH] get rid of hand coded padding , add crypto_secretbox(), add crypto_pwhash_scrypt()
Hello Michael, the following patch adds and changes a couple of things: 1) I replaced the crypto_box[_open] functions with their _easy counterparts and removed the padding code, since the _easy functions in libsodium already implement this. 2) I added crypto_secretbox() and crypto_secretbox_open() for symmetric encryption. 3) I added crypto_pwhash_salt() to generate a salt and crypto_pwhash_scrypt() to derive a secure key from a passphrase. I also added a couple of constants required for those changes. POD updated accordingly. Usage sample: use Crypt::Sodium; use MIME::Base64; # sym encrypt my $n = crypto_box_nonce(); my $k = randombytes_buf(32); my $m = 'hello'; # sym decrypt my $c = crypto_secretbox($m, $n, $k); my $a = crypto_secretbox_open($c, $n, $k); print "ok\n" if ($a eq $m); # gen salt for keygen my $salt = crypto_pwhash_salt(); print encode_base64($salt); # derive a key my $hash = crypto_pwhash_scrypt($m, $salt, 128); # repeat my $hash2 = crypto_pwhash_scrypt($m, $salt, 128); print "ok\n" if($hash eq $hash2); best regards, Tom
Subject: crypt-sodium-easy-scrypt-20110319.patch
diff -c Crypt-Sodium-0.06/Sodium.xs Crypt-Sodium-0.07/Sodium.xs *** Crypt-Sodium-0.06/Sodium.xs 2015-01-23 17:27:29.000000000 +0100 --- Crypt-Sodium-0.07/Sodium.xs 2015-03-19 21:48:04.000000000 +0100 *************** *** 53,58 **** --- 53,66 ---- RETVAL SV * + crypto_box_SEEDBYTES() + CODE: + RETVAL = newSVuv((unsigned int) crypto_box_SEEDBYTES); + + OUTPUT: + RETVAL + + SV * crypto_sign_PUBLICKEYBYTES() CODE: RETVAL = newSVuv((unsigned int) crypto_sign_PUBLICKEYBYTES); *************** *** 61,66 **** --- 69,91 ---- RETVAL SV * + crypto_secretbox_MACBYTES() + CODE: + RETVAL = newSVuv((unsigned int) crypto_secretbox_MACBYTES); + + OUTPUT: + RETVAL + + SV * + crypto_box_MACBYTES() + CODE: + RETVAL = newSVuv((unsigned int) crypto_box_MACBYTES); + + OUTPUT: + RETVAL + + + SV * crypto_sign_SECRETKEYBYTES() CODE: RETVAL = newSVuv((unsigned int) crypto_sign_SECRETKEYBYTES); *************** *** 69,74 **** --- 94,123 ---- RETVAL SV * + crypto_pwhash_SALTBYTES() + CODE: + RETVAL = newSVuv((unsigned int) crypto_pwhash_scryptsalsa208sha256_SALTBYTES); + + OUTPUT: + RETVAL + + SV * + crypto_pwhash_OPSLIMIT() + CODE: + RETVAL = newSVuv((unsigned int) crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE); + + OUTPUT: + RETVAL + + SV * + crypto_pwhash_MEMLIMIT() + CODE: + RETVAL = newSVuv((unsigned int) crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE); + + OUTPUT: + RETVAL + + SV * randombytes_random() CODE: uint32_t r_bytes = randombytes_random(); *************** *** 126,182 **** unsigned char * sk CODE: ! int padding_required = 0; ! unsigned long original_clen = clen; ! ! int bytes_of_zeroes = crypto_box_BOXZEROBYTES; ! unsigned char * padding[bytes_of_zeroes]; ! memset(padding, 0, bytes_of_zeroes); ! ! // check to see if we already have bytes_of_zeroes up front ! if (memcmp(c, padding, bytes_of_zeroes) != 0) { ! // some padding is required, let's determine how much. ! padding_required = 1; ! ! int bytes_in_a_row = bytes_of_zeroes; ! for (bytes_in_a_row = bytes_of_zeroes; bytes_in_a_row > 0; --bytes_in_a_row) { ! if (memcmp(c, padding, bytes_in_a_row) == 0) { ! break; ! } ! } ! ! // this is how many zeroes we have to add. ! bytes_of_zeroes = (bytes_of_zeroes - bytes_in_a_row); ! clen += bytes_of_zeroes; ! } ! ! unsigned char * m = malloc(clen); ! unsigned char * padded_c = malloc(clen); ! ! // do padding if we've determined we have to. ! if (padding_required == 1) { ! // set crypto_box_BOXZEROBYTES zeroes at the beginning ! memset(padded_c, 0, bytes_of_zeroes); ! ! // copy in our payload (including zeroes it may have come with) ! memcpy(padded_c + bytes_of_zeroes, c, original_clen); ! } else { ! // just copy the message, it's already good to go. ! memcpy(padded_c, c, clen); ! } ! int status = crypto_box_open((unsigned char *)m, (const unsigned char*)padded_c, (unsigned long long) clen, (const unsigned char*)n, (const unsigned char*)pk, (const unsigned char*)sk); //printf("open_crypto_box Status is: %d\n", status); - // get rid of the zero padding... - unsigned char cleartext[(clen - crypto_box_ZEROBYTES) + 1]; - memcpy( cleartext, &m[crypto_box_ZEROBYTES], clen - crypto_box_ZEROBYTES ); - cleartext[(clen - crypto_box_ZEROBYTES)] = 0; - if (status == 0) { ! RETVAL = newSVpv( cleartext, clen - crypto_box_ZEROBYTES ); } else { RETVAL = &PL_sv_undef; } --- 175,189 ---- unsigned char * sk CODE: ! unsigned char * m = malloc(clen - crypto_box_MACBYTES); ! int status = crypto_box_open_easy((unsigned char *)m, (const unsigned char*)c, (unsigned long long) clen, (const unsigned char*)n, (const unsigned char*)pk, (const unsigned char*)sk); //printf("open_crypto_box Status is: %d\n", status); if (status == 0) { ! RETVAL = newSVpv( m, clen - crypto_box_MACBYTES ); } else { RETVAL = &PL_sv_undef; } *************** *** 193,262 **** unsigned char * sk CODE: ! int padding_required = 0; ! unsigned long original_mlen = mlen; ! int bytes_of_zeroes = crypto_box_ZEROBYTES; ! unsigned char * padding[bytes_of_zeroes]; ! memset(padding, 0, bytes_of_zeroes); ! ! // check to see if we already have bytes_of_zeroes up front ! if (memcmp(m, padding, crypto_box_ZEROBYTES) != 0) { ! // some padding is required, let's determine how much. ! padding_required = 1; ! ! int bytes_in_a_row = bytes_of_zeroes; ! for (bytes_in_a_row = bytes_of_zeroes; bytes_in_a_row > 0; --bytes_in_a_row) { ! if (memcmp(m, padding, bytes_in_a_row) == 0) { ! break; ! } ! } ! ! // this is how many zeroes we have to add. ! bytes_of_zeroes = (bytes_of_zeroes - bytes_in_a_row); ! mlen += bytes_of_zeroes; ! } ! unsigned char * c = malloc(mlen); ! unsigned char * padded_m = malloc(mlen); ! // do padding if we've determined we have to. ! if (padding_required == 1) { ! // set crypto_box_ZEROBYTES zeroes at the beginning ! memset(padded_m, 0, bytes_of_zeroes); ! // copy in our payload (including zeroes it may have come with) ! memcpy(padded_m + bytes_of_zeroes, m, original_mlen); } else { ! // just copy the message, it's already good to go. ! memcpy(padded_m, m, mlen); } ! int status = crypto_box((unsigned char *)c, (const unsigned char*)padded_m, ! (unsigned long long) mlen, (const unsigned char*)n, (const unsigned char*)pk, (const unsigned char*)sk); - //printf("crypto_box Status is: %d\n", status); ! // the message is at least this big. ! unsigned char ciphertext[mlen]; ! int clen = 0; ! int i; ! for (i = 0; i < mlen; i++) { ! if ( !(c[i] == 0) || (clen > 0) ) { ! ciphertext[clen] = c[i]; ! clen++; ! } ! } ! // make sure to terminate ! ciphertext[clen + 1] = 0; ! RETVAL = newSVpv( ciphertext, clen ); OUTPUT: RETVAL SV * real_crypto_hash(in, inlen) unsigned char * in --- 200,270 ---- unsigned char * sk CODE: ! unsigned char * c = malloc(mlen + crypto_box_MACBYTES); ! int status = crypto_box_easy((unsigned char *)c, (const unsigned char*)m, ! (unsigned long long) mlen, (const unsigned char*)n, (const unsigned char*)pk, (const unsigned char*)sk); ! ! //printf("crypto_box Status is: %d\n", status); ! if (status == 0) { ! RETVAL = newSVpv( c, mlen + crypto_box_MACBYTES); ! } else { ! RETVAL = &PL_sv_undef; ! } ! ! OUTPUT: ! RETVAL ! ! ! SV * ! real_crypto_secretbox_open(c, clen, n, sk) ! unsigned char * c ! unsigned long clen ! unsigned char * n ! unsigned char * sk ! ! CODE: ! unsigned char * m = malloc(clen - crypto_secretbox_MACBYTES); ! int status = crypto_secretbox_open_easy((unsigned char *)m, (const unsigned char*)c, ! (unsigned long long) clen, (const unsigned char*)n, (const unsigned char*)sk); ! if (status == 0) { ! RETVAL = newSVpv( m, clen - crypto_secretbox_MACBYTES ); } else { ! RETVAL = &PL_sv_undef; } ! OUTPUT: ! RETVAL ! SV * ! real_crypto_secretbox(m, mlen, n, sk) ! unsigned char * m ! unsigned long mlen ! unsigned char * n ! unsigned char * sk ! CODE: ! unsigned char * c = malloc(mlen + crypto_secretbox_MACBYTES); ! int status = crypto_secretbox_easy((unsigned char *)c, (const unsigned char*)m, ! (unsigned long long) mlen, (const unsigned char*)n, (const unsigned char*)sk); ! if (status == 0) { ! RETVAL = newSVpv( c, mlen + crypto_secretbox_MACBYTES ); ! } else { ! RETVAL = &PL_sv_undef; ! } OUTPUT: RETVAL + + + SV * real_crypto_hash(in, inlen) unsigned char * in *************** *** 353,355 **** --- 361,386 ---- OUTPUT: RETVAL + + SV * + real_crypto_pwhash_scrypt(klen, p, salt, opslimit, memlimit) + unsigned long klen + unsigned char *p + unsigned char *salt + unsigned long opslimit + unsigned long memlimit + + CODE: + unsigned char *k = malloc(klen); + + int status = crypto_pwhash_scryptsalsa208sha256((unsigned char *)k, klen, + (unsigned char *)p, strlen(p), (const unsigned char *)salt, opslimit, memlimit); + + if (status == 0) { + RETVAL = newSVpv((unsigned char *)k, klen); + } else { + RETVAL = &PL_sv_undef; + } + + OUTPUT: + RETVAL Common subdirectories: Crypt-Sodium-0.06/lib and Crypt-Sodium-0.07/lib Common subdirectories: Crypt-Sodium-0.06/t and Crypt-Sodium-0.07/t
Tom, Thank you very much for the patch! You mentioned updating POD, and are calling new functions in your examples, but (and I might be missing something, I only use RT a few times a year) it seems that the provided patch is only updating Sodium.xs. I am very grateful for your contribution and cleanup, and don't have a problem writing the documentation and changes to Sodium.pm myself, but I don't want to do the work over again if you already had done it! So if you have the rest of the patch, please attach it here, or, if I am totally missing something if you wouldn't mind nudging me in the appropriate direction. Also, if I am just misreading and need to add it myself, just let me know and I'll finish it up and put a 0.07 release together. Thanks again, -Mike
Oh dammit, I forgot the -r diff switch. My bad, here's the patch for Sodium.pm. -Tom
Subject: crypt-sodium-easy-scrypt-sodiumpm-20110319.patch
*** Crypt-Sodium-0.06/lib/Crypt/Sodium.pm 2015-01-23 17:33:17.000000000 +0100 --- Crypt-Sodium-0.07/lib/Crypt/Sodium.pm 2015-03-19 21:56:36.000000000 +0100 *************** *** 19,24 **** --- 19,28 ---- real_crypto_box crypto_box_open real_crypto_box_open + crypto_secretbox + real_crypto_secretbox + crypto_secretbox_open + real_crypto_secretbox_open crypto_hash real_crypto_hash crypto_stream *************** *** 39,47 **** crypto_stream_key crypto_stream_nonce crypto_box_nonce ); ! our $VERSION = '0.06'; use subs qw/ crypto_stream_KEYBYTES --- 43,53 ---- crypto_stream_key crypto_stream_nonce crypto_box_nonce + crypto_pwhash_salt + crypto_pwhash_scrypt ); ! our $VERSION = '0.07'; use subs qw/ crypto_stream_KEYBYTES *************** *** 49,56 **** --- 55,68 ---- crypto_box_NONCEBYTES crypto_box_PUBLICKEYBYTES crypto_box_SECRETKEYBYTES + crypto_box_MACBYTES + crypto_secretbox_MACBYTES crypto_sign_PUBLICKEYBYTES crypto_sign_SECRETKEYBYTES + crypto_pwhash_SALTBYTES + crypto_pwhash_OPSLIMIT + crypto_pwhash_MEMLIMIT + crypto_box_SEEDBYTES /; require XSLoader; *************** *** 159,164 **** --- 171,226 ---- return real_crypto_box($m, length($m), $n, $pk, $sk); } + sub crypto_secretbox_open { + my ($c, $n, $sk) = @_; + + unless (length($sk) == crypto_box_SECRETKEYBYTES) { + die "[fatal]: secret key must be exactly " . crypto_box_SECRETKEYBYTES . " bytes long.\n"; + } + + return real_crypto_secretbox_open($c, length($c), $n, $sk); + } + + sub crypto_secretbox { + my ($m, $n, $sk) = @_; + + unless (length($sk) == crypto_box_SECRETKEYBYTES) { + die "[fatal]: secret key must be exactly " . crypto_box_SECRETKEYBYTES . " bytes long.\n"; + } + + return real_crypto_secretbox($m, length($m), $n, $sk); + } + + sub crypto_pwhash_salt { + return randombytes_buf(crypto_pwhash_SALTBYTES); + } + + sub crypto_pwhash_scrypt { + my ($pass, $salt, $klen, $ops, $mem) = @_; + + if (length($pass) < 1) { + die "[fatal]: supplying a zero length passphrase doesn't make any sense.\n"; + } + + if (length($salt) < crypto_pwhash_SALTBYTES) { + die "[fatal]: salt must be exactly " . crypto_pwhash_SALTBYTES . " bytes long.\n"; + } + + if (! $klen) { + $klen = crypto_box_SEEDBYTES; + } + + if (! $ops) { + $ops = crypto_pwhash_OPSLIMIT; + } + + if (! $mem) { + $mem = crypto_pwhash_OPSLIMIT; + } + + return real_crypto_pwhash_scrypt($klen, $pass, $salt, $ops, $mem); + } + # Preloaded methods go here. 1; *************** *** 209,214 **** --- 271,284 ---- crypto_box_open($ciphertext, $nonce, $public_key, $secret_key) Usage: my $cleartext = crypto_box_open($c, $n, $pk, $sk); + crypto_secretbox($message, $nonce, $key); + Usage: my $ciphertext = crypto_secretbox($m, $n, $k); + Note: $nonce must be at least crypto_box_NONCEBYTES long, + $key must be at least crypto_box_SECRETKEYBYTES long. + + crypto_secretbox_open($ciphertext, $nonce, $key); + Usage: my $message = crypto_secretbox($c, $n, $k); + crypto_hash($to_hash) Usage: my $hash = crypto_hash($to_hash); *************** *** 234,239 **** --- 304,320 ---- crypto_stream_key() Usage: my $key = crypto_stream_key() + crypto_pwhash_salt() + Usage: my $salt = crypto_pwhash_salt(); + + crypto_pwhash_scrypt($pass, $salt, $keylen, $opslimit, $memlimit) + Usage: my $derivedkey = crypto_pwhash_scrypt($pass, $salt, $keylen, $opslimit, $memlimit); + Note: $salt must be crypto_pwhash_SALTBYTES long, use crypto_pwhash_salt() to generate + $keylen maybe omitted, the default is crypto_box_SEEDBYTES + $opslimit maybe omitted, the default is crypto_pwhash_OPSLIMIT + $memlimit maybe omitted, the default is crypto_pwhash_MEMLIMIT + See L<http://doc.libsodium.org/password_hashing/README.html> for details>. + =head1 SEE ALSO https://github.com/jedisct1/libsodium
Thanks for the patch. I added the _str version of the pwhash function and the _verify function as well. Thanks for bringing these library changes to my attention. I'll try and keep up with the times a bit better in the future :). Fixed in 0.07 release submitted to CPAN. https://metacpan.org/release/MGREGORO/Crypt-Sodium-0.07