1  /*-
       2   * Copyright 2013-2018 Alexander Peslyak
       3   * All rights reserved.
       4   *
       5   * Redistribution and use in source and binary forms, with or without
       6   * modification, are permitted.
       7   *
       8   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
       9   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      10   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      11   * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
      12   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      13   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      14   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      15   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      16   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      17   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      18   * SUCH DAMAGE.
      19   */
      20  
      21  #include "crypt-port.h"
      22  
      23  #if INCLUDE_yescrypt || INCLUDE_scrypt || INCLUDE_gost_yescrypt
      24  
      25  #pragma GCC diagnostic ignored "-Wconversion"
      26  #pragma GCC diagnostic ignored "-Wsign-conversion"
      27  #pragma GCC diagnostic ignored "-Wcast-qual"
      28  
      29  #include <stdio.h>
      30  #include <string.h>
      31  
      32  #define YESCRYPT_FLAGS YESCRYPT_DEFAULTS
      33  #if 1
      34  #define YESCRYPT_P 11
      35  #define YESCRYPT_PROM 8
      36  #else
      37  #define YESCRYPT_P 1
      38  #define YESCRYPT_PROM 1
      39  #endif
      40  
      41  #undef  TEST_PBKDF2_SHA256
      42  #define TEST_SCRYPT
      43  #define TEST_YESCRYPT_KDF
      44  #define TEST_YESCRYPT_ENCODING
      45  #define TEST_ROM
      46  #define TEST_ROM_PREALLOC
      47  
      48  static int retval = 0;
      49  
      50  #ifdef TEST_ROM_PREALLOC
      51  #include <stdlib.h> /* for malloc() */
      52  #endif
      53  
      54  #ifdef TEST_PBKDF2_SHA256
      55  #include <assert.h>
      56  
      57  #include "alg-sha256.h"
      58  
      59  static void print_PBKDF2_SHA256_raw(const char *passwd, size_t passwdlen,
      60      const char *salt, size_t saltlen, uint64_t c, size_t dkLen)
      61  {
      62  	uint8_t dk[64];
      63  	size_t i;
      64  
      65  	assert(dkLen <= sizeof(dk));
      66  
      67  	/* XXX This prints the strings truncated at first NUL */
      68  	printf("PBKDF2_SHA256(\"%s\", \"%s\", %llu, %llu) =",
      69  	    passwd, salt, (unsigned long long)c, (unsigned long long)dkLen);
      70  
      71  	PBKDF2_SHA256((const uint8_t *) passwd, passwdlen,
      72  	    (const uint8_t *) salt, saltlen, c, dk, dkLen);
      73  
      74  	for (i = 0; i < dkLen; i++)
      75  		printf(" %02x", dk[i]);
      76  	puts("");
      77  }
      78  
      79  static void print_PBKDF2_SHA256(const char *passwd,
      80      const char *salt, uint64_t c, size_t dkLen)
      81  {
      82  	print_PBKDF2_SHA256_raw(passwd, strlen(passwd), salt, strlen(salt), c,
      83  	    dkLen);
      84  }
      85  #endif
      86  
      87  #if defined(TEST_SCRYPT) || defined(TEST_YESCRYPT_ENCODING)
      88  #include "alg-yescrypt.h"
      89  #endif
      90  
      91  #ifdef TEST_SCRYPT
      92  static void print_scrypt(const char *passwd, const char *salt,
      93      uint64_t N, uint32_t r, uint32_t p)
      94  {
      95  	uint8_t dk[64];
      96  	size_t i;
      97  
      98  	printf("scrypt(\"%s\", \"%s\", %llu, %u, %u) =",
      99  	    passwd, salt, (unsigned long long)N, r, p);
     100  
     101  	if (crypto_scrypt((const uint8_t *) passwd, strlen(passwd),
     102  	    (const uint8_t *) salt, strlen(salt), N, r, p, dk, sizeof(dk))) {
     103  		puts(" FAILED");
     104  		retval = 1;
     105  		return;
     106  	}
     107  
     108  	for (i = 0; i < sizeof(dk); i++)
     109  		printf(" %02x", dk[i]);
     110  	puts("");
     111  }
     112  #endif
     113  
     114  #ifdef TEST_YESCRYPT_KDF
     115  static void print_yescrypt(const char *passwd, const char *salt,
     116      yescrypt_flags_t flags,
     117      uint64_t N, uint32_t r, uint32_t p, uint32_t t, uint32_t g,
     118      uint32_t dklen)
     119  {
     120  	yescrypt_local_t local;
     121  	yescrypt_params_t params = {flags, N, r, p, t, g, 0};
     122  	uint8_t dk[64];
     123  	uint32_t i;
     124  
     125  #if 1
     126  	/* Don't test hash upgrades */
     127  	if (g)
     128  		return;
     129  #endif
     130  
     131  	if (dklen > sizeof(dk) || yescrypt_init_local(&local)) {
     132  		puts("FAILED");
     133  		retval = 1;
     134  		return;
     135  	}
     136  
     137  	printf("yescrypt(\"%s\", \"%s\", %u, %llu, %u, %u, %u, %u) =",
     138  	    passwd, salt, flags, (unsigned long long)N, r, p, t, g);
     139  
     140  	if (yescrypt_kdf(NULL, &local,
     141  	    (const uint8_t *) passwd, strlen(passwd),
     142  	    (const uint8_t *) salt, strlen(salt), ¶ms, dk, dklen)) {
     143  		yescrypt_free_local(&local);
     144  		puts(" FAILED");
     145  		retval = 1;
     146  		return;
     147  	}
     148  
     149  	yescrypt_free_local(&local);
     150  
     151  	for (i = 0; i < dklen; i++)
     152  		printf(" %02x", dk[i]);
     153  	puts("");
     154  }
     155  #endif
     156  
     157  int main(void)
     158  {
     159  	int i;
     160  
     161  	setvbuf(stdout, NULL, _IOLBF, 0);
     162  
     163  #ifdef TEST_PBKDF2_SHA256
     164  	print_PBKDF2_SHA256("password", "salt", 1, 20);
     165  	print_PBKDF2_SHA256("password", "salt", 2, 20);
     166  	print_PBKDF2_SHA256("password", "salt", 4096, 20);
     167  	print_PBKDF2_SHA256("password", "salt", 16777216, 20);
     168  	print_PBKDF2_SHA256("passwordPASSWORDpassword",
     169  	    "saltSALTsaltSALTsaltSALTsaltSALTsalt", 4096, 25);
     170  	print_PBKDF2_SHA256_raw("pass\0word", 9, "sa\0lt", 5, 4096, 16);
     171  #if 0
     172  	print_PBKDF2_SHA256("password", "salt", 1, 32);
     173  	print_PBKDF2_SHA256("password", "salt", 2, 32);
     174  	print_PBKDF2_SHA256("password", "salt", 4096, 32);
     175  	print_PBKDF2_SHA256("password", "salt", 16777216, 32);
     176  	print_PBKDF2_SHA256("passwordPASSWORDpassword",
     177  	    "saltSALTsaltSALTsaltSALTsaltSALTsalt", 4096, 40);
     178  	print_PBKDF2_SHA256("password", "salt", 4096, 16);
     179  	print_PBKDF2_SHA256("password", "salt", 1, 20);
     180  	print_PBKDF2_SHA256("password", "salt", 2, 20);
     181  	print_PBKDF2_SHA256("password", "salt", 4096, 20);
     182  	print_PBKDF2_SHA256("password", "salt", 16777216, 20);
     183  	print_PBKDF2_SHA256("password", "salt", 4096, 25);
     184  	print_PBKDF2_SHA256("password", "salt", 4096, 16);
     185  #endif
     186  #endif
     187  
     188  #ifdef TEST_SCRYPT
     189  	print_scrypt("", "", 16, 1, 1);
     190  	print_scrypt("password", "NaCl", 1024, 8, 16);
     191  	print_scrypt("pleaseletmein", "SodiumChloride", 16384, 8, 1);
     192  	print_scrypt("pleaseletmein", "SodiumChloride", 1048576, 8, 1);
     193  #endif
     194  
     195  #ifdef TEST_YESCRYPT_KDF
     196  	print_yescrypt("", "", 0, 16, 1, 1, 0, 0, 64);
     197  	print_yescrypt("", "", 0, 16, 1, 1, 0, 0, 8);
     198  	print_yescrypt("", "", 0, 4, 1, 1, 0, 0, 64);
     199  	print_yescrypt("", "", YESCRYPT_WORM, 4, 1, 1, 0, 0, 64);
     200  	print_yescrypt("", "", YESCRYPT_WORM, 4, 1, 1, 0, 0, 8);
     201  	print_yescrypt("", "", YESCRYPT_WORM, 4, 1, 1, 1, 0, 64);
     202  	print_yescrypt("", "", YESCRYPT_WORM, 4, 1, 1, 2, 0, 64);
     203  	print_yescrypt("", "", YESCRYPT_WORM, 4, 1, 1, 3, 0, 64);
     204  	print_yescrypt("", "", YESCRYPT_WORM, 4, 1, 1, 3, 0, 33);
     205  	print_yescrypt("", "", YESCRYPT_WORM, 4, 1, 1, 3, 0, 32);
     206  	print_yescrypt("", "", YESCRYPT_WORM, 4, 1, 1, 3, 0, 31);
     207  	print_yescrypt("", "", YESCRYPT_WORM, 4, 1, 1, 3, 0, 1);
     208  	print_yescrypt("", "", YESCRYPT_DEFAULTS, 4, 1, 1, 0, 0, 64);
     209  	print_yescrypt("", "", YESCRYPT_DEFAULTS, 4, 1, 1, 0, 0, 4);
     210  	print_yescrypt("", "", YESCRYPT_DEFAULTS, 4, 1, 1, 1, 0, 64);
     211  	print_yescrypt("", "", YESCRYPT_DEFAULTS, 4, 1, 1, 1, 0, 33);
     212  	print_yescrypt("", "", YESCRYPT_DEFAULTS, 4, 1, 1, 1, 0, 32);
     213  	print_yescrypt("", "", YESCRYPT_DEFAULTS, 4, 1, 1, 1, 0, 31);
     214  	print_yescrypt("", "", YESCRYPT_DEFAULTS, 4, 1, 1, 1, 0, 1);
     215  	for (i = 0; i <= 6; i++)
     216  		print_yescrypt("p", "s", YESCRYPT_DEFAULTS, 16, 8, 1, i + 10, i, 40);
     217  	for (i = 0; i <= 6; i++)
     218  		print_yescrypt("p", "s", YESCRYPT_WORM, 16, 8, 1, i + 10, i, 40);
     219  	for (i = 0; i <= 6; i++)
     220  		print_yescrypt("p", "s", YESCRYPT_DEFAULTS, 16, 8, 1, 0, i, 40);
     221  	for (i = 0; i <= 6; i++)
     222  		print_yescrypt("p", "s", YESCRYPT_WORM, 16, 8, 1, 0, i, 40);
     223  	for (i = 0; i <= 2; i++)
     224  		print_yescrypt("p", "s", YESCRYPT_DEFAULTS, 16, 8, 1, 0, i, 32);
     225  	for (i = 0; i <= 2; i++)
     226  		print_yescrypt("p", "s", YESCRYPT_DEFAULTS, 16, 8, 1, 0, i, 8);
     227  #endif
     228  
     229  #ifdef TEST_YESCRYPT_ENCODING
     230  	{
     231  		uint8_t *setting;
     232  		yescrypt_binary_t key = {.uc={
     233  		    1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
     234  		    17,18,19,20,21,22,23,24,25,26,27,28,255,128,64,32}};
     235  
     236  		for (i = 0; i < 18; i++) {
     237  			uint32_t N_log2 = (i < 14) ? (16 - i) : 2;
     238  			uint32_t r = (i < 8) ? (8 - i) : (1 + (i & 1));
     239  			uint32_t p = (i & 1) ? 1 : YESCRYPT_P;
     240  			yescrypt_flags_t flags = YESCRYPT_DEFAULTS;
     241  			if ((int)p - (i / 2) > 1)
     242  				p -= i / 2;
     243  			if (i & 2) {
     244  				flags = YESCRYPT_WORM;
     245  			} else {
     246  				while ((1ULL << N_log2) / p <= 3)
     247  					N_log2++;
     248  			}
     249  			yescrypt_params_t params =
     250  			    {flags, (uint64_t)1 << N_log2, r, p, 0, 0, 0};
     251  			setting = yescrypt_encode_params(¶ms,
     252  			    (const uint8_t *)"WZaPV7LSUEKMo34.", 16 - (i & 15));
     253  			if (setting && i == 0)
     254  				printf("'%s'\n", (char *)setting);
     255  			if (!setting) {
     256  				printf("%d yescrypt_encode_params() = NULL\n", i);
     257  				retval = 1;
     258  			}
     259  			if (setting) {
     260  				uint8_t *hash = yescrypt(
     261  				    (const uint8_t *)"pleaseletmein", setting);
     262  				printf("Plaintext: '%s'\n", (char *)hash);
     263  				hash = (uint8_t *)strdup((char *)hash);
     264  				if (!hash || strcmp(
     265  				    (char *)hash, (char *)yescrypt(
     266  				    (const uint8_t *)"pleaseletmein", hash))) {
     267  					puts("Validation FAILED");
     268  					retval = 1;
     269  				}
     270  				uint8_t *orig = (uint8_t *)strdup((char *)hash);
     271  				if (!yescrypt_reencrypt(hash, NULL, &key)) {
     272  					printf("%d yescrypt_reencrypt() = NULL\n", i);
     273  					retval = 1;
     274  				}
     275  				printf("Encrypted: '%s'\n", (char *)hash);
     276  				yescrypt_local_t local;
     277  				if (yescrypt_init_local(&local)) {
     278  					puts("yescrypt_init_local() FAILED");
     279  					retval = 1;
     280  				}
     281  				uint8_t buf[128];
     282  				if (strcmp((char *)hash, (char *)yescrypt_r(
     283  				    NULL, &local,
     284  				    (const uint8_t *)"pleaseletmein", 13,
     285  				    hash, &key, buf, sizeof(buf)))) {
     286  					puts("Validation of encrypted FAILED");
     287  					retval = 1;
     288  				}
     289  				if (!strcmp((char *)hash, (char *)yescrypt_r(
     290  				    NULL, &local,
     291  				    (const uint8_t *)"pleaseletmein", 13,
     292  				    hash, NULL, buf, sizeof(buf)))) {
     293  					puts("Validation of encrypted "
     294  					"unexpectedly succeeded");
     295  					retval = 1;
     296  				}
     297  				if (!strcmp((char *)orig, (char *)yescrypt_r(
     298  				    NULL, &local,
     299  				    (const uint8_t *)"pleaseletmein", 13,
     300  				    orig, &key, buf, sizeof(buf)))) {
     301  					puts("Validation of unencrypted "
     302  					"unexpectedly succeeded");
     303  					retval = 1;
     304  				}
     305  				yescrypt_free_local(&local);
     306  				if (!yescrypt_reencrypt(hash, &key, NULL)) {
     307  					printf("%d yescrypt_reencrypt() = NULL\n", i);
     308  					retval = 1;
     309  				}
     310  				if (strcmp((char *)hash, (char *)orig)) {
     311  					puts("Decryption FAILED");
     312  					retval = 1;
     313  				}
     314  				free(orig);
     315  				free(hash);
     316  			}
     317  		}
     318  
     319  		printf("'%s'\n", (char *)yescrypt(
     320  		    (const uint8_t *)"pleaseletmein",
     321  		    (const uint8_t *)"$7$C6..../....SodiumChloride"));
     322  
     323  		printf("'%s'\n", (char *)yescrypt(
     324  		    (const uint8_t *)"pleaseletmein",
     325  		    (const uint8_t *)"$7$06..../....SodiumChloride"));
     326  
     327  #ifdef TEST_ROM
     328  		uint64_t rom_bytes = 256 * (1024ULL*1024);
     329  		uint64_t ram_bytes = 2 * (1024ULL*1024);
     330  		uint32_t r;
     331  		uint64_t NROM_log2, N_log2;
     332  		yescrypt_shared_t shared;
     333  		yescrypt_local_t local;
     334  
     335  		NROM_log2 = 0;
     336  		while (((rom_bytes >> NROM_log2) & 0xff) == 0)
     337  			NROM_log2++;
     338  		r = rom_bytes >> (7 + NROM_log2);
     339  		while (r < 5 && NROM_log2 > 0) {
     340  			r <<= 1;
     341  			NROM_log2--;
     342  		}
     343  		rom_bytes = (uint64_t)r << (7 + NROM_log2);
     344  
     345  		N_log2 = 0;
     346  		while (((uint64_t)r << (7 + N_log2)) < ram_bytes)
     347  			N_log2++;
     348  		ram_bytes = (uint64_t)r << (7 + N_log2);
     349  
     350  		printf("r=%u N=2^%u NROM=2^%u\n", r,
     351  		    (unsigned int)N_log2, (unsigned int)NROM_log2);
     352  
     353  		printf("Will use %.2f KiB ROM\n", rom_bytes / 1024.0);
     354  		printf("         %.2f KiB RAM\n", ram_bytes / 1024.0);
     355  
     356  		printf("Initializing ROM ...");
     357  		fflush(stdout);
     358  		yescrypt_params_t rom_params = { YESCRYPT_DEFAULTS,
     359  		    0, r, YESCRYPT_PROM, 0, 0, (uint64_t)1 << NROM_log2 };
     360  		if (yescrypt_init_shared(&shared,
     361  		    (uint8_t *)"local param", 12, &rom_params)) {
     362  			puts(" FAILED");
     363  			retval = 1;
     364  		}
     365  		yescrypt_binary_t *digest = yescrypt_digest_shared(&shared);
     366  		printf(" DONE (%02x%02x%02x%02x)\n",
     367  		    digest->uc[0], digest->uc[1], digest->uc[2], digest->uc[3]);
     368  
     369  		if (yescrypt_init_local(&local)) {
     370  			puts("FAILED");
     371  			retval = 1;
     372  		}
     373  
     374  		yescrypt_params_t params = rom_params;
     375  		params.flags = YESCRYPT_FLAGS;
     376  		params.N = (uint64_t)1 << N_log2;
     377  		params.p = YESCRYPT_P;
     378  		setting = yescrypt_encode_params(¶ms,
     379  		    (const uint8_t *)"WZaPV7LSUEKMo34.", 16);
     380  		printf("'%s'\n", (char *)setting);
     381  
     382  		uint8_t hash[128];
     383  
     384  		printf("'%s'\n", (char *)yescrypt_r(&shared, &local,
     385  		    (const uint8_t *)"pleaseletmein", 13, setting, NULL,
     386  		    hash, sizeof(hash)));
     387  
     388  #ifdef TEST_ROM_PREALLOC
     389  		yescrypt_free_shared(&shared);
     390  
     391  		shared.aligned_size = ((uint64_t)1 << NROM_log2) * 128 * r;
     392  		shared.base_size = shared.aligned_size + 63;
     393  		uint8_t *where = shared.base = malloc(shared.base_size);
     394  		where += 63;
     395  		where = shared.aligned = where - ((uintptr_t)where & 63);
     396  
     397  		printf("Initializing ROM in preallocated memory ...");
     398  		fflush(stdout);
     399  		rom_params.flags |= YESCRYPT_SHARED_PREALLOCATED;
     400  		if (yescrypt_init_shared(&shared,
     401  		    (uint8_t *)"local param", 12, &rom_params)) {
     402  			puts(" FAILED");
     403  			retval = 1;
     404  		}
     405  		digest = yescrypt_digest_shared(&shared);
     406  		printf(" DONE (%02x%02x%02x%02x)\n",
     407  		    digest->uc[0], digest->uc[1], digest->uc[2], digest->uc[3]);
     408  
     409  		if ((void *)where != shared.aligned) {
     410  			puts("YESCRYPT_SHARED_PREALLOCATED failed");
     411  			retval = 1;
     412  		}
     413  
     414  #endif
     415  
     416  		printf("'%s'\n", (char *)yescrypt_r(&shared, &local,
     417  		    (const uint8_t *)"pleaseletmein", 13, setting, NULL,
     418  		    hash, sizeof(hash)));
     419  
     420  		printf("'%s'\n", (char *)yescrypt_r(&shared, &local,
     421  		    (const uint8_t *)"pleaseletmeIn", 13, setting, NULL,
     422  		    hash, sizeof(hash)));
     423  
     424  		setting = yescrypt_encode_params(¶ms,
     425  		    (const uint8_t *)"WZaPV7LSUEIMo34.", 16);
     426  
     427  		printf("'%s'\n", (char *)yescrypt_r(&shared, &local,
     428  		    (const uint8_t *)"pleaseletmein", 13, setting, NULL,
     429  		    hash, sizeof(hash)));
     430  
     431  		printf("'%s'\n", (char *)yescrypt_r(&shared, &local,
     432  		    (const uint8_t *)"pleaseletmeIn", 13, setting, NULL,
     433  		    hash, sizeof(hash)));
     434  
     435  		params.N = 4;
     436  		params.NROM *= params.r;
     437  		params.r = 1;
     438  		params.p = 1;
     439  		setting = yescrypt_encode_params(¶ms,
     440  		    (const uint8_t *)"WZaPV7LSUEKMo34.", 16);
     441  
     442  		printf("'%s'\n", (char *)yescrypt_r(&shared, &local,
     443  		    (const uint8_t *)"pleaseletmein", 13, setting, NULL,
     444  		    hash, sizeof(hash)));
     445  
     446  		free(shared.base); /* has been malloc'ed */
     447  		shared.base = NULL;
     448  		yescrypt_free_shared(&shared);
     449  #endif
     450  	}
     451  #endif
     452  
     453  	return retval;
     454  }
     455  
     456  #else
     457  
     458  int
     459  main (void)
     460  {
     461  	return 77; /* UNSUPPORTED */
     462  }
     463  
     464  #endif /* INCLUDE_yescrypt || INCLUDE_scrypt || INCLUDE_gost_yescrypt */