Skip to content

Commit

Permalink
Various fixes to avoid potential conflicts with php/php-src#1997
Browse files Browse the repository at this point in the history
- Added Windows config script for building on Windows
- Updated tests
- Renamed constants from PASSWORD_ARGON* to ARGON*_PASSWORD
  to avoid potential conflicts with php/php-src#1997
- Bumping version for API change
  • Loading branch information
charlesportwoodii committed Jul 13, 2016
1 parent 84b8918 commit a883d51
Show file tree
Hide file tree
Showing 10 changed files with 91 additions and 60 deletions.
14 changes: 9 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,20 +57,24 @@ If `make test` encounters an error, please provide a copy of the error report as
The following constants are exposed for determining which Argon2 algorithm you wish to use:

```php
PASSWORD_ARGON2I
PASSWORD_ARGON2D
ARGON2I_PASSWORD
ARGON2D_PASSWORD
```

The constant `ARGON2I_PASSWORD` can also be aliased by `ARGON2_PASSWORD`.

> These constants are named to avoid conflicts with https://github.com/php/php-src/pull/1997, which would implement Argon2 in PHP Core.
### Hash Generation

```php
argon2_hash(string $password [, const $algorithm = PASSWORD_ARGON2I] [, array $options ]);
argon2_hash(string $password [, const $algorithm = ARGON2I_PASSWORD] [, array $options ]);
```

Hashes can be generated by running `argon2_hash()` with the string password you want to see hashed. Without any additional arguements, the hash generated will have the following options. These defaults are based upon the Argon2 specification as good minimums. You are encouraged to run `make bench` against the `ext/argon2` to determine what are good defaults for your system.

```bash
algorithm = PASSWORD_ARGON2I
algorithm = ARGON2I_PASSWORD
options = [
m_cost: 1<<16
t_cost: 3
Expand All @@ -81,7 +85,7 @@ options = [
> This function follows the same design principles of `password_hash()`, in that a salt will be generated on your behalf. This method does not provide you with a way to provide your own salt. The salt generated uses the native PHP function `php_password_make_salt`, which is the same method used to generate salts for `password_hash()`.

The `$algorithm` can be changed by passing in either `PASSWORD_ARGON2I` or `PASSWORD_ARGON2D`. If the algorithm is invalid, an `InvalidArguementException` will be raised.
The `$algorithm` can be changed by passing in either `ARGON2I_PASSWORD` or `ARGON2D_PASSWORD`. If the algorithm is invalid, an `InvalidArguementException` will be raised.

This library allows you to specify an array of options to tune Argon2 to your system. The available options for the `$options` array, and their defaults are defined above. Argon2 has several tolerances in place for each of these values. If the value falls outside those tolerances, and `InvalidArguementException` will be raised.

Expand Down
41 changes: 21 additions & 20 deletions argon2.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,13 +94,13 @@ PHP_FUNCTION(argon2_hash)
{
// Argon2 Options
uint32_t t_cost = 3;
uint32_t m_cost = (1<<16); // 64 MiB
uint32_t m_cost = (1<<16);
uint32_t lanes = 1;
uint32_t threads = 1;
uint32_t out_len = 32;
argon2_type type = Argon2_i; // Default to Argon2_i
argon2_type type = EXT_PASSWORD_ARGON2I;

size_t salt_len = 16; // 16 Byte salt
size_t salt_len = 16;
size_t password_len;
size_t encoded_len;

Expand All @@ -122,23 +122,23 @@ PHP_FUNCTION(argon2_hash)
Z_PARAM_LONG(argon2_type)
Z_PARAM_ARRAY_HT(options);
ZEND_PARSE_PARAMETERS_END();

// Determine the m_cost if it was passed via options
if (options && (option_buffer = zend_hash_str_find(options, "m_cost", sizeof("m_cost")-1)) != NULL) {
m_cost = zval_get_long(option_buffer);
}

if (m_cost > ARGON2_MAX_MEMORY) {
zend_throw_exception(spl_ce_InvalidArgumentException, "`m_cost` exceeds maximum memory", 0 TSRMLS_CC);
if (m_cost > ARGON2_MAX_MEMORY || m_cost == 0) {
zend_throw_exception(spl_ce_InvalidArgumentException, "Memory cost is not valid", 0 TSRMLS_CC);
}

// Determine the t_cost if it was passed via options
if (options && (option_buffer = zend_hash_str_find(options, "t_cost", sizeof("t_cost")-1)) != NULL) {
t_cost = zval_get_long(option_buffer);
}

if (t_cost > ARGON2_MAX_TIME) {
zend_throw_exception(spl_ce_InvalidArgumentException, "`t_cost` exceeds maximum time", 0 TSRMLS_CC);
if (t_cost > ARGON2_MAX_TIME || t_cost == 0) {
zend_throw_exception(spl_ce_InvalidArgumentException, "Time cost is not valid", 0 TSRMLS_CC);
}

// Determine the parallelism degree if it was passed via options
Expand All @@ -147,7 +147,7 @@ PHP_FUNCTION(argon2_hash)
}

if (threads > ARGON2_MAX_LANES || threads == 0) {
zend_throw_exception(spl_ce_InvalidArgumentException, "Invalid numeric input for `threads`", 0 TSRMLS_CC);
zend_throw_exception(spl_ce_InvalidArgumentException, "Number of threads is not valid", 0 TSRMLS_CC);
}

lanes = threads;
Expand All @@ -156,12 +156,12 @@ PHP_FUNCTION(argon2_hash)
if (password_len == 0) {
zend_throw_exception(spl_ce_InvalidArgumentException, "Password must be provided", 0 TSRMLS_CC);
}

// Determine the Algorithm type
if (argon2_type == Argon2_i || argon2_type == -1) {
type = Argon2_i;
} else if (argon2_type == Argon2_d) {
type = Argon2_d;
if (argon2_type == EXT_PASSWORD_ARGON2I || argon2_type == -1) {
type = EXT_PASSWORD_ARGON2I;
} else if (argon2_type == EXT_PASSWORD_ARGON2D) {
type = EXT_PASSWORD_ARGON2D;
} else {
zend_throw_exception(spl_ce_InvalidArgumentException, "Algorithm must be one of `PASSWORD_ARGON2_D, PASSWORD_ARGON2_I`", 0 TSRMLS_CC);
}
Expand Down Expand Up @@ -228,7 +228,7 @@ Generates an argon2 hash */
PHP_FUNCTION(argon2_verify)
{
// Argon2 Options
argon2_type type = Argon2_i; // Default to Argon2_i
argon2_type type = EXT_PASSWORD_ARGON2I; // Default to Argon2_i

size_t password_len;
size_t encoded_len;
Expand All @@ -245,9 +245,9 @@ PHP_FUNCTION(argon2_verify)

// Determine which algorithm is used
if (strstr(encoded, "argon2d")) {
type = Argon2_d;
type = EXT_PASSWORD_ARGON2D;
} else if (strstr(encoded, "argon2i")) {
type = Argon2_i;
type = EXT_PASSWORD_ARGON2I;
} else {
zend_throw_exception(spl_ce_InvalidArgumentException, "Invalid Argon2 hash", 0 TSRMLS_CC);
}
Expand Down Expand Up @@ -276,9 +276,10 @@ const zend_function_entry argon2_functions[] = {
*/
PHP_MINIT_FUNCTION(argon2)
{
// Create contants for ARGON2
REGISTER_LONG_CONSTANT("PASSWORD_ARGON2D", Argon2_d, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PASSWORD_ARGON2I", Argon2_i, CONST_CS | CONST_PERSISTENT);
// Create contants for Argon2
REGISTER_LONG_CONSTANT("ARGON2D_PASSWORD", EXT_PASSWORD_ARGON2D, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("ARGON2I_PASSWORD", EXT_PASSWORD_ARGON2I, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("ARGON2_PASSWORD", EXT_PASSWORD_ARGON2, CONST_CS | CONST_PERSISTENT);

return SUCCESS;
}
Expand Down
13 changes: 13 additions & 0 deletions config.w32
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// vim:ft=javascript
// $Id$

ARG_WITH("argon2", "Argon2 support", "no");

if (PHP_ARGON2 != "no") {
if (CHECK_LIB("Argon2Ref.lib", null, PHP_ARGON2)
&& CHECK_HEADER_ADD_INCLUDE("argon2.h", "CFLAGS")) {
AC_DEFINE('HAVE_ARGON2LIB', 1);
} else {
WARNING("Argon2 not enabled; libaries and headers not found");
}
}
6 changes: 5 additions & 1 deletion php_argon2.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@
#define argon2_module_ptr &argon2_module_entry
#define phpext_argon2_ptr argon2_module_ptr

#define PHP_ARGON2_VERSION "1.0.2"
#define PHP_ARGON2_VERSION "1.1.0"

#define EXT_PASSWORD_ARGON2I Argon2_i
#define EXT_PASSWORD_ARGON2D Argon2_d
#define EXT_PASSWORD_ARGON2 EXT_PASSWORD_ARGON2I

#ifdef ZTS
#include "TSRM.h"
Expand Down
10 changes: 6 additions & 4 deletions tests/argon2_001.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
Tests Argon2 constants are defined
--FILE--
<?php
var_dump(PASSWORD_ARGON2D);
var_dump(PASSWORD_ARGON2I);
var_dump(ARGON2_PASSWORD);
var_dump(ARGON2I_PASSWORD);
var_dump(ARGON2D_PASSWORD);
--EXPECT--
int(0)
int(1)
int(1)
int(1)
int(0)
2 changes: 1 addition & 1 deletion tests/argon2_003.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Tests Argon2i hash and verify
--FILE--
<?php
$hash = argon2_hash('password', PASSWORD_ARGON2I);
$hash = argon2_hash('password', ARGON2I_PASSWORD);
var_dump(argon2_verify('password', $hash));
var_dump(argon2_verify('badpass', $hash));
--EXPECT--
Expand Down
2 changes: 1 addition & 1 deletion tests/argon2_004.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Tests Argon2d hash and verify
--FILE--
<?php
$hash = argon2_hash('password', PASSWORD_ARGON2D);
$hash = argon2_hash('password', ARGON2D_PASSWORD);
var_dump(argon2_verify('password', $hash));
var_dump(argon2_verify('badpass', $hash));
--EXPECT--
Expand Down
24 changes: 12 additions & 12 deletions tests/argon2_005.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -3,51 +3,51 @@ Tests Argon2i hash and verify with options
--FILE--
<?php
$password = 'password';
$hash = argon2_hash($password, PASSWORD_ARGON2I, [ 'm_cost' => 17 ]);
$hash = argon2_hash($password, ARGON2I_PASSWORD, [ 'm_cost' => 17 ]);
var_dump(argon2_verify($password, $hash));
var_dump(argon2_verify('wrongpassword', $hash));

$hash = argon2_hash($password, PASSWORD_ARGON2I, [ 'm_cost' => 20 ]);
$hash = argon2_hash($password, ARGON2I_PASSWORD, [ 'm_cost' => 20 ]);
var_dump(argon2_verify($password, $hash));
var_dump(argon2_verify('wrongpassword', $hash));

$hash = argon2_hash($password, PASSWORD_ARGON2I, [ 't_cost' => 1 ]);
$hash = argon2_hash($password, ARGON2I_PASSWORD, [ 't_cost' => 1 ]);
var_dump(argon2_verify($password, $hash));
var_dump(argon2_verify('wrongpassword', $hash));

$hash = argon2_hash($password, PASSWORD_ARGON2I, [ 't_cost' => 2 ]);
$hash = argon2_hash($password, ARGON2I_PASSWORD, [ 't_cost' => 2 ]);
var_dump(argon2_verify($password, $hash));
var_dump(argon2_verify('wrongpassword', $hash));

$hash = argon2_hash($password, PASSWORD_ARGON2I, [ 't_cost' => 3 ]);
$hash = argon2_hash($password, ARGON2I_PASSWORD, [ 't_cost' => 3 ]);
var_dump(argon2_verify($password, $hash));
var_dump(argon2_verify('wrongpassword', $hash));

$hash = argon2_hash($password, PASSWORD_ARGON2I, [ 't_cost' => 3 ]);
$hash = argon2_hash($password, ARGON2I_PASSWORD, [ 't_cost' => 3 ]);
var_dump(argon2_verify($password, $hash));
var_dump(argon2_verify('wrongpassword', $hash));

$hash = argon2_hash($password, PASSWORD_ARGON2I, [ 'm_cost' => 16, 't_cost' => 1 ]);
$hash = argon2_hash($password, ARGON2I_PASSWORD, [ 'm_cost' => 16, 't_cost' => 1 ]);
var_dump(argon2_verify($password, $hash));
var_dump(argon2_verify('wrongpassword', $hash));

$hash = argon2_hash($password, PASSWORD_ARGON2I, [ 'm_cost' => 18, 't_cost' => 2 ]);
$hash = argon2_hash($password, ARGON2I_PASSWORD, [ 'm_cost' => 18, 't_cost' => 2 ]);
var_dump(argon2_verify($password, $hash));
var_dump(argon2_verify('wrongpassword', $hash));

$hash = argon2_hash($password, PASSWORD_ARGON2I, [ 'm_cost' => 20, 't_cost' => 3 ]);
$hash = argon2_hash($password, ARGON2I_PASSWORD, [ 'm_cost' => 20, 't_cost' => 3 ]);
var_dump(argon2_verify($password, $hash));
var_dump(argon2_verify('wrongpassword', $hash));

$hash = argon2_hash($password, PASSWORD_ARGON2I, [ 'm_cost' => 17, 't_cost' => 1, 'threads' => 1 ]);
$hash = argon2_hash($password, ARGON2I_PASSWORD, [ 'm_cost' => 17, 't_cost' => 1, 'threads' => 1 ]);
var_dump(argon2_verify($password, $hash));
var_dump(argon2_verify('wrongpassword', $hash));

$hash = argon2_hash($password, PASSWORD_ARGON2I, [ 'm_cost' => 30, 't_cost' => 2, 'threads' => 2 ]);
$hash = argon2_hash($password, ARGON2I_PASSWORD, [ 'm_cost' => 30, 't_cost' => 2, 'threads' => 2 ]);
var_dump(argon2_verify($password, $hash));
var_dump(argon2_verify('wrongpassword', $hash));

$hash = argon2_hash($password, PASSWORD_ARGON2I, [ 'm_cost' => 30, 't_cost' => 3, 'threads' => 3 ]);
$hash = argon2_hash($password, ARGON2I_PASSWORD, [ 'm_cost' => 30, 't_cost' => 3, 'threads' => 3 ]);
var_dump(argon2_verify($password, $hash));
var_dump(argon2_verify('wrongpassword', $hash));
--EXPECT--
Expand Down
24 changes: 12 additions & 12 deletions tests/argon2_006.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -3,51 +3,51 @@ Tests Argon2d hash and verify with options
--FILE--
<?php
$password = 'password';
$hash = argon2_hash($password, PASSWORD_ARGON2D, [ 'm_cost' => 17 ]);
$hash = argon2_hash($password, ARGON2D_PASSWORD, [ 'm_cost' => 17 ]);
var_dump(argon2_verify($password, $hash));
var_dump(argon2_verify('wrongpassword', $hash));

$hash = argon2_hash($password, PASSWORD_ARGON2D, [ 'm_cost' => 20 ]);
$hash = argon2_hash($password, ARGON2D_PASSWORD, [ 'm_cost' => 20 ]);
var_dump(argon2_verify($password, $hash));
var_dump(argon2_verify('wrongpassword', $hash));

$hash = argon2_hash($password, PASSWORD_ARGON2D, [ 't_cost' => 1 ]);
$hash = argon2_hash($password, ARGON2D_PASSWORD, [ 't_cost' => 1 ]);
var_dump(argon2_verify($password, $hash));
var_dump(argon2_verify('wrongpassword', $hash));

$hash = argon2_hash($password, PASSWORD_ARGON2D, [ 't_cost' => 2 ]);
$hash = argon2_hash($password, ARGON2D_PASSWORD, [ 't_cost' => 2 ]);
var_dump(argon2_verify($password, $hash));
var_dump(argon2_verify('wrongpassword', $hash));

$hash = argon2_hash($password, PASSWORD_ARGON2D, [ 't_cost' => 3 ]);
$hash = argon2_hash($password, ARGON2D_PASSWORD, [ 't_cost' => 3 ]);
var_dump(argon2_verify($password, $hash));
var_dump(argon2_verify('wrongpassword', $hash));

$hash = argon2_hash($password, PASSWORD_ARGON2D, [ 't_cost' => 3 ]);
$hash = argon2_hash($password, ARGON2D_PASSWORD, [ 't_cost' => 3 ]);
var_dump(argon2_verify($password, $hash));
var_dump(argon2_verify('wrongpassword', $hash));

$hash = argon2_hash($password, PASSWORD_ARGON2D, [ 'm_cost' => 16, 't_cost' => 1 ]);
$hash = argon2_hash($password, ARGON2D_PASSWORD, [ 'm_cost' => 16, 't_cost' => 1 ]);
var_dump(argon2_verify($password, $hash));
var_dump(argon2_verify('wrongpassword', $hash));

$hash = argon2_hash($password, PASSWORD_ARGON2D, [ 'm_cost' => 18, 't_cost' => 2 ]);
$hash = argon2_hash($password, ARGON2D_PASSWORD, [ 'm_cost' => 18, 't_cost' => 2 ]);
var_dump(argon2_verify($password, $hash));
var_dump(argon2_verify('wrongpassword', $hash));

$hash = argon2_hash($password, PASSWORD_ARGON2D, [ 'm_cost' => 20, 't_cost' => 3 ]);
$hash = argon2_hash($password, ARGON2D_PASSWORD, [ 'm_cost' => 20, 't_cost' => 3 ]);
var_dump(argon2_verify($password, $hash));
var_dump(argon2_verify('wrongpassword', $hash));

$hash = argon2_hash($password, PASSWORD_ARGON2D, [ 'm_cost' => 17, 't_cost' => 1, 'threads' => 1 ]);
$hash = argon2_hash($password, ARGON2D_PASSWORD, [ 'm_cost' => 17, 't_cost' => 1, 'threads' => 1 ]);
var_dump(argon2_verify($password, $hash));
var_dump(argon2_verify('wrongpassword', $hash));

$hash = argon2_hash($password, PASSWORD_ARGON2D, [ 'm_cost' => 30, 't_cost' => 2, 'threads' => 2 ]);
$hash = argon2_hash($password, ARGON2D_PASSWORD, [ 'm_cost' => 30, 't_cost' => 2, 'threads' => 2 ]);
var_dump(argon2_verify($password, $hash));
var_dump(argon2_verify('wrongpassword', $hash));

$hash = argon2_hash($password, PASSWORD_ARGON2D, [ 'm_cost' => 30, 't_cost' => 3, 'threads' => 3 ]);
$hash = argon2_hash($password, ARGON2D_PASSWORD, [ 'm_cost' => 30, 't_cost' => 3, 'threads' => 3 ]);
var_dump(argon2_verify($password, $hash));
var_dump(argon2_verify('wrongpassword', $hash));
--EXPECT--
Expand Down
15 changes: 11 additions & 4 deletions tests/argon2_007.phpt
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
--TEST--
Tests Argon2 low memory RuntimeException
Tests Argon2 exceptions
--FILE--
<?php
try {
$hash = argon2_hash('test', PASSWORD_ARGON2I, ['m_cost' => 0]);
$hash = argon2_hash('test', ARGON2_PASSWORD, ['m_cost' => 0]);
} catch (RuntimeException $e) {
var_dump($e->getMessage());
}

try {
$hash = argon2_hash('test', PASSWORD_ARGON2D, ['m_cost' => 0]);
$hash = argon2_hash('test', ARGON2_PASSWORD, ['t_cost' => 0]);
} catch (RuntimeException $e) {
var_dump($e->getMessage());
}

try {
$hash = argon2_hash('test', ARGON2_PASSWORD, ['threads' => 0]);
} catch (RuntimeException $e) {
var_dump($e->getMessage());
}
--EXPECT--
string(24) "Memory cost is too small"
string(24) "Memory cost is too small"
string(22) "Time cost is too small"
string(13) "Too few lanes"

0 comments on commit a883d51

Please sign in to comment.