浏览代码

add bcrypt

Steffen Jaeckel 6 年之前
父节点
当前提交
9423f3b26d
共有 8 个文件被更改,包括 414 次插入2 次删除
  1. 32 2
      doc/crypt.tex
  2. 10 0
      src/headers/tomcrypt_custom.h
  3. 7 0
      src/headers/tomcrypt_misc.h
  4. 201 0
      src/misc/bcrypt/bcrypt.c
  5. 4 0
      src/misc/crypt/crypt.c
  6. 156 0
      tests/bcrypt_test.c
  7. 3 0
      tests/misc_test.c
  8. 1 0
      tests/tomcrypt_test.h

+ 32 - 2
doc/crypt.tex

@@ -7002,7 +7002,7 @@ for completeness.  Algorithm Two is a bit more modern and more flexible to work
 
 
 The OpenSSL project implemented an extension to Algorithm One that allows for arbitrary keylengths; we have a compatible implementation described below.
 The OpenSSL project implemented an extension to Algorithm One that allows for arbitrary keylengths; we have a compatible implementation described below.
 
 
-\subsection{Algorithm One}
+\subsubsection{Algorithm One}
 Algorithm One accepts as input a password, an 8--byte salt, and an iteration counter.  The iteration counter is meant to act as delay for
 Algorithm One accepts as input a password, an 8--byte salt, and an iteration counter.  The iteration counter is meant to act as delay for
 people trying to brute force guess the password.  The higher the iteration counter the longer the delay.  This algorithm also requires a hash
 people trying to brute force guess the password.  The higher the iteration counter the longer the delay.  This algorithm also requires a hash
 algorithm and produces an output no longer than the output of the hash.
 algorithm and produces an output no longer than the output of the hash.
@@ -7035,7 +7035,7 @@ int pkcs_5_alg1_openssl(const unsigned char *password,
                       unsigned long *outlen)
                       unsigned long *outlen)
 \end{alltt}
 \end{alltt}
 As above, but we generate as many bytes as requested in outlen per the OpenSSL extension to Algorithm One.  If you are trying to be compatible with OpenSSL's EVP\_BytesToKey() or the "openssl enc" command line (or variants such as perl's Crypt::CBC), then use this function with MD5 as your hash (ick!) and iteration\_count=1 (double-ick!!).
 As above, but we generate as many bytes as requested in outlen per the OpenSSL extension to Algorithm One.  If you are trying to be compatible with OpenSSL's EVP\_BytesToKey() or the "openssl enc" command line (or variants such as perl's Crypt::CBC), then use this function with MD5 as your hash (ick!) and iteration\_count=1 (double-ick!!).
-\subsection{Algorithm Two}
+\subsubsection{Algorithm Two}
 
 
 Algorithm Two is the recommended algorithm for this task.  It allows variable length salts, and can produce outputs larger than the
 Algorithm Two is the recommended algorithm for this task.  It allows variable length salts, and can produce outputs larger than the
 hash functions output.  As such, it can easily be used to derive session keys for ciphers and MACs as well initialization vectors as required
 hash functions output.  As such, it can easily be used to derive session keys for ciphers and MACs as well initialization vectors as required
@@ -7091,6 +7091,35 @@ int main(void)
 }
 }
 \end{verbatim}
 \end{verbatim}
 
 
+
+\subsection{bcrypt}
+\index{bcrypt}
+
+bcrypt is a password hashing function, similar to PKCS \#5, but it is based on the blowfish symmetric cipher.
+It is widely used in e.g. OpenBSD as default password hash algorithm, or in encrypted OpenSSH key files.
+
+This implementation provides the PBKDF version as used in OpenSSH key files.
+
+The OpenBSD implementation is fixed to SHA512 as hashing algorithm, but this generalized implementation works with any hashing algorithm.
+
+To hash a password with the bcrypt PBKDF algorithm, the following API function is provided.
+
+\index{bcrypt()}
+\begin{alltt}
+int bcrypt_pbkdf_openbsd(const          char *password, unsigned long password_len,
+                         const unsigned char *salt,     unsigned long salt_len,
+                               unsigned int  rounds,              int hash_idx,
+                               unsigned char *out,      unsigned long *outlen);
+\end{alltt}
+
+The \textit{password} parameter is the utf-8 encoded user password of length \textit{password\_len}.
+The \textit{salt} parameter is a pointer to the array of octets of length \textit{salt\_len} containing the salt.
+The \textit{rounds} parameter defines the number of iterations of the expensive key setup that shall be executed.
+The \textit{hash\_idx} parameter defines the hash algorithm that shall be used. 
+The \textit{out} parameter shall be a pointer to a buffer of at least 32 octets,
+where \textit{outlen} contains the available buffer size on input and the written size after the invocation.
+
+
 \mysection{PKCS \#8}
 \mysection{PKCS \#8}
 \index{PKCS \#8}
 \index{PKCS \#8}
 
 
@@ -7127,6 +7156,7 @@ The library supports the following encryption algorithms:
 The PKCS \#8 import has no direct API endpoints, but it is available through Public Key Algorithm-specific
 The PKCS \#8 import has no direct API endpoints, but it is available through Public Key Algorithm-specific
 \textit{pkaX\_import\_pkcs8()} functions.
 \textit{pkaX\_import\_pkcs8()} functions.
 
 
+
 \mysection{Key Derviation Functions}
 \mysection{Key Derviation Functions}
 \subsection{HKDF}
 \subsection{HKDF}
 \index{HKDF}
 \index{HKDF}

+ 10 - 0
src/headers/tomcrypt_custom.h

@@ -490,6 +490,12 @@
 /* Base16/hex encoding/decoding */
 /* Base16/hex encoding/decoding */
 #define LTC_BASE16
 #define LTC_BASE16
 
 
+#define LTC_BCRYPT
+
+#ifndef LTC_BCRYPT_DEFAULT_ROUNDS
+#define LTC_BCRYPT_DEFAULT_ROUNDS 10
+#endif
+
 /* Keep LTC_NO_HKDF for compatibility reasons
 /* Keep LTC_NO_HKDF for compatibility reasons
  * superseeded by LTC_NO_MISC*/
  * superseeded by LTC_NO_MISC*/
 #ifndef LTC_NO_HKDF
 #ifndef LTC_NO_HKDF
@@ -601,6 +607,10 @@
    #error PK requires ASN.1 DER functionality, make sure LTC_DER is enabled
    #error PK requires ASN.1 DER functionality, make sure LTC_DER is enabled
 #endif
 #endif
 
 
+#if defined(LTC_BCRYPT) && !defined(LTC_BLOWFISH)
+   #error LTC_BCRYPT requires LTC_BLOWFISH
+#endif
+
 #if defined(LTC_CHACHA20POLY1305_MODE) && (!defined(LTC_CHACHA) || !defined(LTC_POLY1305))
 #if defined(LTC_CHACHA20POLY1305_MODE) && (!defined(LTC_CHACHA) || !defined(LTC_POLY1305))
    #error LTC_CHACHA20POLY1305_MODE requires LTC_CHACHA + LTC_POLY1305
    #error LTC_CHACHA20POLY1305_MODE requires LTC_CHACHA + LTC_POLY1305
 #endif
 #endif

+ 7 - 0
src/headers/tomcrypt_misc.h

@@ -59,6 +59,13 @@ int base16_decode(const          char *in,  unsigned long  inlen,
                         unsigned char *out, unsigned long *outlen);
                         unsigned char *out, unsigned long *outlen);
 #endif
 #endif
 
 
+#ifdef LTC_BCRYPT
+int bcrypt_pbkdf_openbsd(const          char *password, unsigned long password_len,
+                         const unsigned char *salt,     unsigned long salt_len,
+                               unsigned int  rounds,              int hash_idx,
+                               unsigned char *out,      unsigned long *outlen);
+#endif
+
 /* ===> LTC_HKDF -- RFC5869 HMAC-based Key Derivation Function <=== */
 /* ===> LTC_HKDF -- RFC5869 HMAC-based Key Derivation Function <=== */
 #ifdef LTC_HKDF
 #ifdef LTC_HKDF
 
 

+ 201 - 0
src/misc/bcrypt/bcrypt.c

@@ -0,0 +1,201 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt_private.h"
+
+/**
+   @file bcrypt.c
+   bcrypt pbkdf, Steffen Jaeckel
+*/
+#ifdef LTC_BCRYPT
+
+#define BCRYPT_WORDS 8
+#define BCRYPT_HASHSIZE (BCRYPT_WORDS * 4)
+
+static int _bcrypt_hash(const unsigned char *pt,
+                        const unsigned char *pass, unsigned long passlen,
+                        const unsigned char *salt, unsigned long saltlen,
+                              unsigned char *out,  unsigned long *outlen)
+{
+   symmetric_key key;
+   int err, n;
+   ulong32 ct[BCRYPT_WORDS];
+
+   if ((err = blowfish_setup_with_data(pass, passlen, salt, saltlen, &key)) != CRYPT_OK) {
+      return err;
+   }
+   for (n = 0; n < 64; ++n) {
+      if ((err = blowfish_expand(salt, saltlen, NULL, 0, &key)) != CRYPT_OK) {
+         return err;
+      }
+      if ((err = blowfish_expand(pass, passlen, NULL, 0, &key)) != CRYPT_OK) {
+         return err;
+      }
+   }
+
+   for (n = 0; n < BCRYPT_WORDS; ++n) {
+      LOAD32H(ct[n], &pt[n*4]);
+   }
+
+   for (n = 0; n < 64; ++n) {
+      blowfish_enc(ct, BCRYPT_WORDS/2, &key);
+   }
+
+   for (n = 0; n < BCRYPT_WORDS; ++n) {
+      STORE32L(ct[n], &out[4 * n]);
+   }
+   *outlen = sizeof(ct);
+#ifdef LTC_CLEAN_STACK
+   zeromem(&key, sizeof(key));
+   zeromem(ct, sizeof(ct));
+#endif
+
+   return CRYPT_OK;
+}
+
+static int _bcrypt_pbkdf_hash(const unsigned char *pass, unsigned long passlen,
+                         const unsigned char *salt, unsigned long saltlen,
+                               unsigned char *out,  unsigned long *outlen)
+{
+   const unsigned char pt[] = "OxychromaticBlowfishSwatDynamite";
+   return _bcrypt_hash(pt, pass, passlen, salt, saltlen, out, outlen);
+}
+
+/**
+   Compatible to bcrypt_pbkdf() as provided in OpenBSD
+   @param password          The input password (or key)
+   @param password_len      The length of the password (octets)
+   @param salt              The salt (or nonce)
+   @param salt_len          The length of the salt (octets)
+   @param rounds            # of iterations desired [read specs for more]
+   @param hash_idx          The index of the hash desired
+   @param out               [out] The destination for this algorithm
+   @param outlen            [in/out] The desired size of the algorithm output
+   @return CRYPT_OK if successful
+*/
+int bcrypt_pbkdf_openbsd(const          char *password, unsigned long password_len,
+                         const unsigned char *salt,     unsigned long salt_len,
+                               unsigned int  rounds,              int hash_idx,
+                               unsigned char *out,      unsigned long *outlen)
+{
+   int err;
+   ulong32 blkno;
+   unsigned long left, itts, x, y, hashed_pass_len, step_size, steps, dest, used_rounds;
+   unsigned char *buf[3], blkbuf[4];
+   unsigned char *hashed_pass;
+
+   LTC_ARGCHK(password != NULL);
+   LTC_ARGCHK(salt     != NULL);
+   LTC_ARGCHK(out      != NULL);
+   LTC_ARGCHK(outlen   != NULL);
+
+   if ((password_len == 0) || (salt_len == 0) || (*outlen == 0)) {
+      return CRYPT_INVALID_ARG;
+   }
+   /* test hash IDX */
+   if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
+      return err;
+   }
+   /* set default value for rounds if not given */
+   if (rounds == 0) {
+      used_rounds = LTC_BCRYPT_DEFAULT_ROUNDS;
+   } else {
+      used_rounds = rounds;
+   }
+
+   buf[0]      = XMALLOC(MAXBLOCKSIZE * 3);
+   hashed_pass = XMALLOC(MAXBLOCKSIZE);
+   if (buf[0] == NULL || hashed_pass == NULL) {
+      if (hashed_pass != NULL) {
+         XFREE(hashed_pass);
+      }
+      if (buf[0] != NULL) {
+         XFREE(buf[0]);
+      }
+      return CRYPT_MEM;
+   }
+   /* buf[1] points to the second block of MAXBLOCKSIZE bytes */
+   buf[1] = buf[0] + MAXBLOCKSIZE;
+   buf[2] = buf[1] + MAXBLOCKSIZE;
+
+   step_size = (*outlen + BCRYPT_HASHSIZE - 1) / BCRYPT_HASHSIZE;
+   steps = (*outlen + step_size - 1) / step_size;
+
+   hashed_pass_len = MAXBLOCKSIZE;
+   if ((err = hash_memory(hash_idx, (unsigned char*)password, password_len, hashed_pass, &hashed_pass_len)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   left   = *outlen;
+   blkno  = 0;
+   while (left != 0) {
+       /* increment and store current block number */
+       ++blkno;
+       STORE32H(blkno, blkbuf);
+
+       /* process block number blkno */
+       zeromem(buf[0], MAXBLOCKSIZE*2);
+
+       x = MAXBLOCKSIZE;
+       if ((err = hash_memory_multi(hash_idx, buf[0], &x,
+                                    salt, salt_len,
+                                    blkbuf, 4,
+                                    NULL, 0)) != CRYPT_OK) {
+          goto LBL_ERR;
+       }
+       y = MAXBLOCKSIZE;
+       if ((err = _bcrypt_pbkdf_hash(hashed_pass, hashed_pass_len, buf[0], x, buf[1], &y)) != CRYPT_OK) {
+          goto LBL_ERR;
+       }
+       XMEMCPY(buf[2], buf[1], y);
+
+       /* now compute repeated and XOR it in buf[2] */
+       for (itts = 1; itts < used_rounds; ++itts) {
+          x = MAXBLOCKSIZE;
+          if ((err = hash_memory(hash_idx, buf[1], y, buf[0], &x)) != CRYPT_OK) {
+             goto LBL_ERR;
+          }
+          y = MAXBLOCKSIZE;
+          if ((err = _bcrypt_pbkdf_hash(hashed_pass, hashed_pass_len, buf[0], x, buf[1], &y)) != CRYPT_OK) {
+             goto LBL_ERR;
+          }
+           for (x = 0; x < y; x++) {
+               buf[2][x] ^= buf[1][x];
+           }
+       }
+
+       /* now emit upto `steps` bytes of buf[2] to output */
+       steps = MIN(steps, left);
+       for (y = 0; y < steps; ++y) {
+          dest = y * step_size + (blkno - 1);
+          if (dest >= *outlen)
+             break;
+          out[dest] = buf[2][y];
+       }
+       left -= y;
+   }
+
+   err = CRYPT_OK;
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(buf[0], MAXBLOCKSIZE*3);
+   zeromem(hashed_pass, MAXBLOCKSIZE);
+#endif
+
+   XFREE(hashed_pass);
+   XFREE(buf[0]);
+
+   return err;
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */

+ 4 - 0
src/misc/crypt/crypt.c

@@ -434,6 +434,10 @@ const char *crypt_build_settings =
 #if defined(LTC_BASE16)
 #if defined(LTC_BASE16)
     " BASE16 "
     " BASE16 "
 #endif
 #endif
+#if defined(LTC_BCRYPT)
+    " BCRYPT "
+    " " NAME_VALUE(LTC_BCRYPT_DEFAULT_ROUNDS) " "
+#endif
 #if defined(LTC_CRC32)
 #if defined(LTC_CRC32)
     " CRC32 "
     " CRC32 "
 #endif
 #endif

+ 156 - 0
tests/bcrypt_test.c

@@ -0,0 +1,156 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include  <tomcrypt_test.h>
+
+#ifdef LTC_BCRYPT
+
+/** These tests were shamelessly c&p'ed from the OpenBSD sources
+ * https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/regress/lib/libutil/bcrypt_pbkdf/bcrypt_pbkdf_test.c */
+
+struct test {
+   unsigned int rounds;
+   unsigned long passlen;
+   const char *password;
+   unsigned long saltlen;
+   const char *salt;
+   unsigned long keylen;
+   const char *key;
+};
+
+struct test tests[] = {
+   /* basic */
+   { 4, 8, "password", 4, "salt", 32,
+   "\x5b\xbf\x0c\xc2\x93\x58\x7f\x1c\x36\x35\x55\x5c\x27\x79\x65\x98"
+   "\xd4\x7e\x57\x90\x71\xbf\x42\x7e\x9d\x8f\xbe\x84\x2a\xba\x34\xd9"
+   },
+   { 4, 8, "password", 1, "", 16,
+   "\xc1\x2b\x56\x62\x35\xee\xe0\x4c\x21\x25\x98\x97\x0a\x57\x9a\x67"
+   },
+   { 4, 1, "", 4, "salt", 16,
+   "\x60\x51\xbe\x18\xc2\xf4\xf8\x2c\xbf\x0e\xfe\xe5\x47\x1b\x4b\xb9"
+   },
+   /* nul bytes in password and string */
+   { 4, 9, "password", 5, "salt", 32,
+   "\x74\x10\xe4\x4c\xf4\xfa\x07\xbf\xaa\xc8\xa9\x28\xb1\x72\x7f\xac"
+   "\x00\x13\x75\xe7\xbf\x73\x84\x37\x0f\x48\xef\xd1\x21\x74\x30\x50"
+   },
+   { 4, 8, "pass\0word", 4, "sa\0lt", 16,
+   "\xc2\xbf\xfd\x9d\xb3\x8f\x65\x69\xef\xef\x43\x72\xf4\xde\x83\xc0"
+   },
+   { 4, 9, "pass\0word", 5, "sa\0lt", 16,
+   "\x4b\xa4\xac\x39\x25\xc0\xe8\xd7\xf0\xcd\xb6\xbb\x16\x84\xa5\x6f"
+   },
+   /* bigger key */
+   { 8, 8, "password", 4, "salt", 64,
+   "\xe1\x36\x7e\xc5\x15\x1a\x33\xfa\xac\x4c\xc1\xc1\x44\xcd\x23\xfa"
+   "\x15\xd5\x54\x84\x93\xec\xc9\x9b\x9b\x5d\x9c\x0d\x3b\x27\xbe\xc7"
+   "\x62\x27\xea\x66\x08\x8b\x84\x9b\x20\xab\x7a\xa4\x78\x01\x02\x46"
+   "\xe7\x4b\xba\x51\x72\x3f\xef\xa9\xf9\x47\x4d\x65\x08\x84\x5e\x8d"
+   },
+   /* more rounds */
+   { 42, 8, "password", 4, "salt", 16,
+   "\x83\x3c\xf0\xdc\xf5\x6d\xb6\x56\x08\xe8\xf0\xdc\x0c\xe8\x82\xbd"
+   },
+   /* longer password */
+   { 8, 446,
+   "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
+   "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
+   "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
+   "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor "
+   "in reprehenderit in voluptate velit esse cillum dolore eu fugiat "
+   "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
+   "sunt in culpa qui officia deserunt mollit anim id est laborum.",
+   6, "salis", 16,
+   "\x10\x97\x8b\x07\x25\x3d\xf5\x7f\x71\xa1\x62\xeb\x0e\x8a\xd3\x0a"
+   },
+   /* "unicode" */
+   { 8,
+   16, "\x0d\xb3\xac\x94\xb3\xee\x53\x28\x4f\x4a\x22\x89\x3b\x3c\x24\xae",
+   16, "\x3a\x62\xf0\xf0\xdb\xce\xf8\x23\xcf\xcc\x85\x48\x56\xea\x10\x28",
+   16, "\x20\x44\x38\x17\x5e\xee\x7c\xe1\x36\xc9\x1b\x49\xa6\x79\x23\xff"
+   },
+   /* very large key */
+   { 8,
+   16, "\x0d\xb3\xac\x94\xb3\xee\x53\x28\x4f\x4a\x22\x89\x3b\x3c\x24\xae",
+   16, "\x3a\x62\xf0\xf0\xdb\xce\xf8\x23\xcf\xcc\x85\x48\x56\xea\x10\x28",
+   256,
+   "\x20\x54\xb9\xff\xf3\x4e\x37\x21\x44\x03\x34\x74\x68\x28\xe9\xed"
+   "\x38\xde\x4b\x72\xe0\xa6\x9a\xdc\x17\x0a\x13\xb5\xe8\xd6\x46\x38"
+   "\x5e\xa4\x03\x4a\xe6\xd2\x66\x00\xee\x23\x32\xc5\xed\x40\xad\x55"
+   "\x7c\x86\xe3\x40\x3f\xbb\x30\xe4\xe1\xdc\x1a\xe0\x6b\x99\xa0\x71"
+   "\x36\x8f\x51\x8d\x2c\x42\x66\x51\xc9\xe7\xe4\x37\xfd\x6c\x91\x5b"
+   "\x1b\xbf\xc3\xa4\xce\xa7\x14\x91\x49\x0e\xa7\xaf\xb7\xdd\x02\x90"
+   "\xa6\x78\xa4\xf4\x41\x12\x8d\xb1\x79\x2e\xab\x27\x76\xb2\x1e\xb4"
+   "\x23\x8e\x07\x15\xad\xd4\x12\x7d\xff\x44\xe4\xb3\xe4\xcc\x4c\x4f"
+   "\x99\x70\x08\x3f\x3f\x74\xbd\x69\x88\x73\xfd\xf6\x48\x84\x4f\x75"
+   "\xc9\xbf\x7f\x9e\x0c\x4d\x9e\x5d\x89\xa7\x78\x39\x97\x49\x29\x66"
+   "\x61\x67\x07\x61\x1c\xb9\x01\xde\x31\xa1\x97\x26\xb6\xe0\x8c\x3a"
+   "\x80\x01\x66\x1f\x2d\x5c\x9d\xcc\x33\xb4\xaa\x07\x2f\x90\xdd\x0b"
+   "\x3f\x54\x8d\x5e\xeb\xa4\x21\x13\x97\xe2\xfb\x06\x2e\x52\x6e\x1d"
+   "\x68\xf4\x6a\x4c\xe2\x56\x18\x5b\x4b\xad\xc2\x68\x5f\xbe\x78\xe1"
+   "\xc7\x65\x7b\x59\xf8\x3a\xb9\xab\x80\xcf\x93\x18\xd6\xad\xd1\xf5"
+   "\x93\x3f\x12\xd6\xf3\x61\x82\xc8\xe8\x11\x5f\x68\x03\x0a\x12\x44"
+   },
+};
+
+int bcrypt_test(void)
+{
+   unsigned long l;
+   unsigned char key[1024];
+   unsigned int i;
+   int idx;
+   struct test *t;
+
+   idx = find_hash("sha512");
+
+   XMEMSET(key, 0, sizeof(key));
+   l = 88;
+   DO(bcrypt_pbkdf_openbsd("password", 8, (unsigned char*)"salt", 4, 0, idx, key, &l));
+   for (i = 1; i < 88; ++i) {
+      key[0] |= key[i];
+   }
+   if (key[0] == 0) {
+      return CRYPT_FAIL_TESTVECTOR;
+   }
+   if (key[88] || key[89] || key[90]) {
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+#if defined(LTC_TEST_DBG) && LTC_TEST_DBG > 1
+   printf("BCRYPT overflow-test OK\n");
+#endif
+
+   for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
+      t = &tests[i];
+      l = t->keylen;
+      XMEMSET(key, 0, sizeof(key));
+      DO(bcrypt_pbkdf_openbsd(t->password, t->passlen, (unsigned char*)t->salt, t->saltlen, t->rounds, idx, key, &l));
+      DO(do_compare_testvector(key, l, (unsigned char*)t->key, t->keylen, "OpenBSD testvectors", i));
+
+#if defined(LTC_TEST_DBG) && LTC_TEST_DBG > 1
+      printf("BCRYPT test #%d OK\n", i);
+#endif
+   }
+
+   return CRYPT_OK;
+}
+
+#else
+
+
+int bcrypt_test(void)
+{
+   return CRYPT_NOP;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */

+ 3 - 0
tests/misc_test.c

@@ -10,6 +10,9 @@
 
 
 int misc_test(void)
 int misc_test(void)
 {
 {
+#ifdef LTC_BCRYPT
+   DO(bcrypt_test());
+#endif
 #ifdef LTC_HKDF
 #ifdef LTC_HKDF
    DO(hkdf_test());
    DO(hkdf_test());
 #endif
 #endif

+ 1 - 0
tests/tomcrypt_test.h

@@ -47,6 +47,7 @@ int padding_test(void);
 int x25519_test(void);
 int x25519_test(void);
 int ed25519_test(void);
 int ed25519_test(void);
 int ssh_test(void);
 int ssh_test(void);
+int bcrypt_test(void);
 
 
 #ifdef LTC_PKCS_1
 #ifdef LTC_PKCS_1
 struct ltc_prng_descriptor* no_prng_desc_get(void);
 struct ltc_prng_descriptor* no_prng_desc_get(void);