remove bcrypt & jwt-cpp as submodules, bring in statically under src

This commit is contained in:
Andrew Bauer 2019-06-23 12:12:12 -05:00
parent 46032385fe
commit 8b37c0e9b0
46 changed files with 9289 additions and 12 deletions

6
.gitmodules vendored
View File

@ -5,9 +5,3 @@
[submodule "web/api/app/Plugin/CakePHP-Enum-Behavior"]
path = web/api/app/Plugin/CakePHP-Enum-Behavior
url = https://github.com/ZoneMinder/CakePHP-Enum-Behavior.git
[submodule "third_party/bcrypt"]
path = third_party/bcrypt
url = https://github.com/ZoneMinder/libbcrypt
[submodule "third_party/jwt-cpp"]
path = third_party/jwt-cpp
url = https://github.com/Thalhammer/jwt-cpp

View File

@ -876,7 +876,7 @@ ADD_MANPAGE_TARGET()
# build a bcrypt static library
set(BUILD_SHARED_LIBS_SAVED "${BUILD_SHARED_LIBS}")
set(BUILD_SHARED_LIBS OFF)
add_subdirectory(third_party/bcrypt)
add_subdirectory(src/bcrypt)
set(BUILD_SHARED_LIBS "${BUILD_SHARED_LIBS_SAVED}")
add_subdirectory(src)

View File

@ -9,7 +9,7 @@ set(ZM_BIN_SRC_FILES zm_box.cpp zm_buffer.cpp zm_camera.cpp zm_comms.cpp zm_conf
# A fix for cmake recompiling the source files for every target.
add_library(zm STATIC ${ZM_BIN_SRC_FILES})
link_directories(../third_party/bcrypt)
link_directories(bcrypt)
add_executable(zmc zmc.cpp)
add_executable(zma zma.cpp)
@ -17,8 +17,8 @@ add_executable(zmu zmu.cpp)
add_executable(zms zms.cpp)
# JWT is a header only library.
include_directories(../third_party/bcrypt/include/bcrypt)
include_directories(../third_party/jwt-cpp/include/jwt-cpp)
include_directories(bcrypt/include/bcrypt)
include_directories(jwt-cpp/include/jwt-cpp)
target_link_libraries(zmc zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS})
target_link_libraries(zma zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS})

90
src/bcrypt/CMakeLists.txt Normal file
View File

@ -0,0 +1,90 @@
###################################################################################
#
# Copyright (c) 2014, webvariants GmbH, http://www.webvariants.de
#
# This file is released under the terms of the MIT license. You can find the
# complete text in the attached LICENSE file or online at:
#
# http://www.opensource.org/licenses/mit-license.php
#
# @author: Tino Rusch (tino.rusch@webvariants.de)
#
###################################################################################
cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
project(bcrypt)
enable_language(ASM)
set(MYLIB_VERSION_MAJOR 1)
set(MYLIB_VERSION_MINOR 0)
set(MYLIB_VERSION_PATCH 0)
set(MYLIB_VERSION_STRING ${MYLIB_VERSION_MAJOR}.${MYLIB_VERSION_MINOR}.${MYLIB_VERSION_PATCH})
# just doing cmake . will build a shared or static lib and honor existing environment setting
# to force build static, cmake . -DBUILD_SHARED_LIBS=Off
# to force build shared, cmake . -DBUILD_SHARED_LIBS=On
if (NOT BUILD_SHARED_LIBS)
message ("Building a static library")
else ()
message ("Building a shared library")
endif ()
set( CMAKE_COLOR_MAKEFILE ON )
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall --std=c++11 -O3" )
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -O3" )
set( CMAKE_ASM_FLAGS "${CXXFLAGS} -x assembler-with-cpp")
set( SRCFILES
${CMAKE_CURRENT_SOURCE_DIR}/src/bcrypt.c
${CMAKE_CURRENT_SOURCE_DIR}/src/crypt_blowfish.c
${CMAKE_CURRENT_SOURCE_DIR}/src/crypt_gensalt.c
${CMAKE_CURRENT_SOURCE_DIR}/src/wrapper.c
${CMAKE_CURRENT_SOURCE_DIR}/src/x86.S
)
include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/include/bcrypt)
include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/include)
add_library(
${PROJECT_NAME}
${SRCFILES}
)
set_target_properties(${PROJECT_NAME} PROPERTIES VERSION ${MYLIB_VERSION_STRING} SOVERSION ${MYLIB_VERSION_MAJOR})
set_target_properties(${PROJECT_NAME} PROPERTIES PUBLIC_HEADER include/bcrypt/BCrypt.hpp)
target_include_directories(${PROJECT_NAME} PRIVATE include)
target_include_directories(${PROJECT_NAME} PRIVATE src)
add_executable( ${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp)
target_link_libraries( ${PROJECT_NAME}_test ${PROJECT_NAME})
include(GNUInstallDirs)
install(TARGETS ${PROJECT_NAME}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR}
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/bcrypt)
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
FILES_MATCHING PATTERN "*.h")
SET(CPACK_GENERATOR "DEB")
SET(CPACK_SET_DESTDIR ON)
SET(CPACK_DEBIAN_PACKAGE_MAINTAINER "Manuel Romei")
SET(CPACK_PACKAGE_VERSION "1.0.0")
SET(CPACK_PACKAGE_VERSION_MAJOR "1")
SET(CPACK_PACKAGE_VERSION_MINOR "0")
SET(CPACK_PACKAGE_VERSION_PATCH "0")
INCLUDE(CPack)

22
src/bcrypt/LICENSE Normal file
View File

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015 trusch
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

40
src/bcrypt/README.md Normal file
View File

@ -0,0 +1,40 @@
# libbcrypt
A c++ wrapper around bcrypt password hashing
## How to build this
This is a CMake based project:
```bash
git clone https://github.com/trusch/libbcrypt
cd libbcrypt
mkdir build
cd build
cmake ..
make
sudo make install
sudo ldconfig
```
## How to use this
Here an example how to use this wrapper class (you can find it in the src/ subdirectory)
```cpp
#include "bcrypt/BCrypt.hpp"
#include <iostream>
int main(){
BCrypt bcrypt;
std::string password = "test";
std::string hash = bcrypt.generateHash(password);
std::cout<<bcrypt.validatePassword(password,hash)<<std::endl;
std::cout<<bcrypt.validatePassword("test1",hash)<<std::endl;
return 0;
}
```
build this with something like this:
```bash
g++ --std=c++11 -lbcrypt main.cpp
```

View File

@ -0,0 +1,32 @@
#ifndef __BCRYPT__
#define __BCRYPT__
#ifdef _WIN32
#include "winbcrypt.h"
#else
#include "bcrypt.h"
#include <string>
#include <stdexcept>
class BCrypt {
public:
static std::string generateHash(const std::string & password, int workload = 12){
char salt[BCRYPT_HASHSIZE];
char hash[BCRYPT_HASHSIZE];
int ret;
ret = bcrypt_gensalt(workload, salt);
if(ret != 0)throw std::runtime_error{"bcrypt: can not generate salt"};
ret = bcrypt_hashpw(password.c_str(), salt, hash);
if(ret != 0)throw std::runtime_error{"bcrypt: can not generate hash"};
return std::string{hash};
}
static bool validatePassword(const std::string & password, const std::string & hash){
return (bcrypt_checkpw(password.c_str(), hash.c_str()) == 0);
}
};
#endif
#endif // __BCRYPT__

View File

@ -0,0 +1,97 @@
#ifndef BCRYPT_H_
#define BCRYPT_H_
/*
* bcrypt wrapper library
*
* Written in 2011, 2013, 2014, 2015 by Ricardo Garcia <r@rg3.name>
*
* To the extent possible under law, the author(s) have dedicated all copyright
* and related and neighboring rights to this software to the public domain
* worldwide. This software is distributed without any warranty.
*
* You should have received a copy of the CC0 Public Domain Dedication along
* with this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#define BCRYPT_HASHSIZE (64)
#ifdef __cplusplus
extern "C" {
#endif
/*
* This function expects a work factor between 4 and 31 and a char array to
* store the resulting generated salt. The char array should typically have
* BCRYPT_HASHSIZE bytes at least. If the provided work factor is not in the
* previous range, it will default to 12.
*
* The return value is zero if the salt could be correctly generated and
* nonzero otherwise.
*
*/
int bcrypt_gensalt(int workfactor, char salt[BCRYPT_HASHSIZE]);
/*
* This function expects a password to be hashed, a salt to hash the password
* with and a char array to leave the result. Both the salt and the hash
* parameters should have room for BCRYPT_HASHSIZE characters at least.
*
* It can also be used to verify a hashed password. In that case, provide the
* expected hash in the salt parameter and verify the output hash is the same
* as the input hash. However, to avoid timing attacks, it's better to use
* bcrypt_checkpw when verifying a password.
*
* The return value is zero if the password could be hashed and nonzero
* otherwise.
*/
int bcrypt_hashpw(const char *passwd, const char salt[BCRYPT_HASHSIZE],
char hash[BCRYPT_HASHSIZE]);
/*
* This function expects a password and a hash to verify the password against.
* The internal implementation is tuned to avoid timing attacks.
*
* The return value will be -1 in case of errors, zero if the provided password
* matches the given hash and greater than zero if no errors are found and the
* passwords don't match.
*
*/
int bcrypt_checkpw(const char *passwd, const char hash[BCRYPT_HASHSIZE]);
/*
* Brief Example
* -------------
*
* Hashing a password:
*
* char salt[BCRYPT_HASHSIZE];
* char hash[BCRYPT_HASHSIZE];
* int ret;
*
* ret = bcrypt_gensalt(12, salt);
* assert(ret == 0);
* ret = bcrypt_hashpw("thepassword", salt, hash);
* assert(ret == 0);
*
*
* Verifying a password:
*
* int ret;
*
* ret = bcrypt_checkpw("thepassword", "expectedhash");
* assert(ret != -1);
*
* if (ret == 0) {
* printf("The password matches\n");
* } else {
* printf("The password does NOT match\n");
* }
*
*/
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,24 @@
/*
* Written by Solar Designer <solar at openwall.com> in 2000-2002.
* No copyright is claimed, and the software is hereby placed in the public
* domain. In case this attempt to disclaim copyright and place the software
* in the public domain is deemed null and void, then the software is
* Copyright (c) 2000-2002 Solar Designer and it is hereby released to the
* general public under the following terms:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* There's ABSOLUTELY NO WARRANTY, express or implied.
*
* See crypt_blowfish.c for more information.
*/
#include <gnu-crypt.h>
#if defined(_OW_SOURCE) || defined(__USE_OW)
#define __SKIP_GNU
#undef __SKIP_OW
#include <ow-crypt.h>
#undef __SKIP_GNU
#endif

View File

@ -0,0 +1,27 @@
/*
* Written by Solar Designer <solar at openwall.com> in 2000-2011.
* No copyright is claimed, and the software is hereby placed in the public
* domain. In case this attempt to disclaim copyright and place the software
* in the public domain is deemed null and void, then the software is
* Copyright (c) 2000-2011 Solar Designer and it is hereby released to the
* general public under the following terms:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* There's ABSOLUTELY NO WARRANTY, express or implied.
*
* See crypt_blowfish.c for more information.
*/
#ifndef _CRYPT_BLOWFISH_H
#define _CRYPT_BLOWFISH_H
extern int _crypt_output_magic(const char *setting, char *output, int size);
extern char *_crypt_blowfish_rn(const char *key, const char *setting,
char *output, int size);
extern char *_crypt_gensalt_blowfish_rn(const char *prefix,
unsigned long count,
const char *input, int size, char *output, int output_size);
#endif

View File

@ -0,0 +1,30 @@
/*
* Written by Solar Designer <solar at openwall.com> in 2000-2011.
* No copyright is claimed, and the software is hereby placed in the public
* domain. In case this attempt to disclaim copyright and place the software
* in the public domain is deemed null and void, then the software is
* Copyright (c) 2000-2011 Solar Designer and it is hereby released to the
* general public under the following terms:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* There's ABSOLUTELY NO WARRANTY, express or implied.
*
* See crypt_blowfish.c for more information.
*/
#ifndef _CRYPT_GENSALT_H
#define _CRYPT_GENSALT_H
extern unsigned char _crypt_itoa64[];
extern char *_crypt_gensalt_traditional_rn(const char *prefix,
unsigned long count,
const char *input, int size, char *output, int output_size);
extern char *_crypt_gensalt_extended_rn(const char *prefix,
unsigned long count,
const char *input, int size, char *output, int output_size);
extern char *_crypt_gensalt_md5_rn(const char *prefix, unsigned long count,
const char *input, int size, char *output, int output_size);
#endif

View File

@ -0,0 +1,43 @@
/*
* Written by Solar Designer <solar at openwall.com> in 2000-2011.
* No copyright is claimed, and the software is hereby placed in the public
* domain. In case this attempt to disclaim copyright and place the software
* in the public domain is deemed null and void, then the software is
* Copyright (c) 2000-2011 Solar Designer and it is hereby released to the
* general public under the following terms:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* There's ABSOLUTELY NO WARRANTY, express or implied.
*
* See crypt_blowfish.c for more information.
*/
#ifndef _OW_CRYPT_H
#define _OW_CRYPT_H
#ifndef __GNUC__
#undef __const
#define __const const
#endif
#ifndef __SKIP_GNU
extern char *crypt(__const char *key, __const char *setting);
extern char *crypt_r(__const char *key, __const char *setting, void *data);
#endif
#ifndef __SKIP_OW
extern char *crypt_rn(__const char *key, __const char *setting,
void *data, int size);
extern char *crypt_ra(__const char *key, __const char *setting,
void **data, int *size);
extern char *crypt_gensalt(__const char *prefix, unsigned long count,
__const char *input, int size);
extern char *crypt_gensalt_rn(__const char *prefix, unsigned long count,
__const char *input, int size, char *output, int output_size);
extern char *crypt_gensalt_ra(__const char *prefix, unsigned long count,
__const char *input, int size);
#endif
#endif

View File

@ -0,0 +1,27 @@
#ifndef __WIN_BCRYPT__H
#define __WIN_BCRYPT__H
#include <iostream>
#include "crypt_blowfish.h"
#include "./bcrypt.h"
class BCrypt {
public:
static std::string generateHash(const std::string & password, int workload = 12) {
char salt[BCRYPT_HASHSIZE];
char hash[BCRYPT_HASHSIZE];
int ret;
ret = bcrypt_gensalt(workload, salt);
if (ret != 0)throw std::runtime_error{ "bcrypt: can not generate salt" };
ret = bcrypt_hashpw(password.c_str(), salt, hash);
if (ret != 0)throw std::runtime_error{ "bcrypt: can not generate hash" };
return std::string{ hash };
}
static bool validatePassword(const std::string & password, const std::string & hash) {
return (bcrypt_checkpw(password.c_str(), hash.c_str()) == 0);
}
};
#endif

230
src/bcrypt/src/bcrypt.c Normal file
View File

@ -0,0 +1,230 @@
/*
* bcrypt wrapper library
*
* Written in 2011, 2013, 2014, 2015 by Ricardo Garcia <r@rg3.name>
*
* To the extent possible under law, the author(s) have dedicated all copyright
* and related and neighboring rights to this software to the public domain
* worldwide. This software is distributed without any warranty.
*
* You should have received a copy of the CC0 Public Domain Dedication along
* with this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#ifdef _WIN32
#elif _WIN64
#else
#include <unistd.h>
#endif
#include <errno.h>
#ifdef _WIN32 || _WIN64
// On windows we need to generate random bytes differently.
typedef __int64 ssize_t;
#define BCRYPT_HASHSIZE 60
#include "../include/bcrypt/bcrypt.h"
#include <windows.h>
#include <wincrypt.h> /* CryptAcquireContext, CryptGenRandom */
#else
#include "bcrypt.h"
#include "ow-crypt.h"
#endif
#define RANDBYTES (16)
static int try_close(int fd)
{
int ret;
for (;;) {
errno = 0;
ret = close(fd);
if (ret == -1 && errno == EINTR)
continue;
break;
}
return ret;
}
static int try_read(int fd, char *out, size_t count)
{
size_t total;
ssize_t partial;
total = 0;
while (total < count)
{
for (;;) {
errno = 0;
partial = read(fd, out + total, count - total);
if (partial == -1 && errno == EINTR)
continue;
break;
}
if (partial < 1)
return -1;
total += partial;
}
return 0;
}
/*
* This is a best effort implementation. Nothing prevents a compiler from
* optimizing this function and making it vulnerable to timing attacks, but
* this method is commonly used in crypto libraries like NaCl.
*
* Return value is zero if both strings are equal and nonzero otherwise.
*/
static int timing_safe_strcmp(const char *str1, const char *str2)
{
const unsigned char *u1;
const unsigned char *u2;
int ret;
int i;
int len1 = strlen(str1);
int len2 = strlen(str2);
/* In our context both strings should always have the same length
* because they will be hashed passwords. */
if (len1 != len2)
return 1;
/* Force unsigned for bitwise operations. */
u1 = (const unsigned char *)str1;
u2 = (const unsigned char *)str2;
ret = 0;
for (i = 0; i < len1; ++i)
ret |= (u1[i] ^ u2[i]);
return ret;
}
int bcrypt_gensalt(int factor, char salt[BCRYPT_HASHSIZE])
{
int fd;
char input[RANDBYTES];
int workf;
char *aux;
// Note: Windows does not have /dev/urandom sadly.
#ifdef _WIN32 || _WIN64
HCRYPTPROV p;
ULONG i;
// Acquire a crypt context for generating random bytes.
if (CryptAcquireContext(&p, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) == FALSE) {
return 1;
}
if (CryptGenRandom(p, RANDBYTES, (BYTE*)input) == FALSE) {
return 2;
}
if (CryptReleaseContext(p, 0) == FALSE) {
return 3;
}
#else
// Get random bytes on Unix/Linux.
fd = open("/dev/urandom", O_RDONLY);
if (fd == -1)
return 1;
if (try_read(fd, input, RANDBYTES) != 0) {
if (try_close(fd) != 0)
return 4;
return 2;
}
if (try_close(fd) != 0)
return 3;
#endif
/* Generate salt. */
workf = (factor < 4 || factor > 31)?12:factor;
aux = crypt_gensalt_rn("$2a$", workf, input, RANDBYTES,
salt, BCRYPT_HASHSIZE);
return (aux == NULL)?5:0;
}
int bcrypt_hashpw(const char *passwd, const char salt[BCRYPT_HASHSIZE], char hash[BCRYPT_HASHSIZE])
{
char *aux;
aux = crypt_rn(passwd, salt, hash, BCRYPT_HASHSIZE);
return (aux == NULL)?1:0;
}
int bcrypt_checkpw(const char *passwd, const char hash[BCRYPT_HASHSIZE])
{
int ret;
char outhash[BCRYPT_HASHSIZE];
ret = bcrypt_hashpw(passwd, hash, outhash);
if (ret != 0)
return -1;
return timing_safe_strcmp(hash, outhash);
}
#ifdef TEST_BCRYPT
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
int main(void)
{
clock_t before;
clock_t after;
char salt[BCRYPT_HASHSIZE];
char hash[BCRYPT_HASHSIZE];
int ret;
const char pass[] = "hi,mom";
const char hash1[] = "$2a$10$VEVmGHy4F4XQMJ3eOZJAUeb.MedU0W10pTPCuf53eHdKJPiSE8sMK";
const char hash2[] = "$2a$10$3F0BVk5t8/aoS.3ddaB3l.fxg5qvafQ9NybxcpXLzMeAt.nVWn.NO";
ret = bcrypt_gensalt(12, salt);
assert(ret == 0);
printf("Generated salt: %s\n", salt);
before = clock();
ret = bcrypt_hashpw("testtesttest", salt, hash);
assert(ret == 0);
after = clock();
printf("Hashed password: %s\n", hash);
printf("Time taken: %f seconds\n",
(double)(after - before) / CLOCKS_PER_SEC);
ret = bcrypt_hashpw(pass, hash1, hash);
assert(ret == 0);
printf("First hash check: %s\n", (strcmp(hash1, hash) == 0)?"OK":"FAIL");
ret = bcrypt_hashpw(pass, hash2, hash);
assert(ret == 0);
printf("Second hash check: %s\n", (strcmp(hash2, hash) == 0)?"OK":"FAIL");
before = clock();
ret = (bcrypt_checkpw(pass, hash1) == 0);
after = clock();
printf("First hash check with bcrypt_checkpw: %s\n", ret?"OK":"FAIL");
printf("Time taken: %f seconds\n",
(double)(after - before) / CLOCKS_PER_SEC);
before = clock();
ret = (bcrypt_checkpw(pass, hash2) == 0);
after = clock();
printf("Second hash check with bcrypt_checkpw: %s\n", ret?"OK":"FAIL");
printf("Time taken: %f seconds\n",
(double)(after - before) / CLOCKS_PER_SEC);
return 0;
}
#endif

View File

@ -0,0 +1,911 @@
/*
* The crypt_blowfish homepage is:
*
* http://www.openwall.com/crypt/
*
* This code comes from John the Ripper password cracker, with reentrant
* and crypt(3) interfaces added, but optimizations specific to password
* cracking removed.
*
* Written by Solar Designer <solar at openwall.com> in 1998-2014.
* No copyright is claimed, and the software is hereby placed in the public
* domain. In case this attempt to disclaim copyright and place the software
* in the public domain is deemed null and void, then the software is
* Copyright (c) 1998-2014 Solar Designer and it is hereby released to the
* general public under the following terms:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* There's ABSOLUTELY NO WARRANTY, express or implied.
*
* It is my intent that you should be able to use this on your system,
* as part of a software package, or anywhere else to improve security,
* ensure compatibility, or for any other purpose. I would appreciate
* it if you give credit where it is due and keep your modifications in
* the public domain as well, but I don't require that in order to let
* you place this code and any modifications you make under a license
* of your choice.
*
* This implementation is fully compatible with OpenBSD's bcrypt.c for prefix
* "$2b$", originally by Niels Provos <provos at citi.umich.edu>, and it uses
* some of his ideas. The password hashing algorithm was designed by David
* Mazieres <dm at lcs.mit.edu>. For information on the level of
* compatibility for bcrypt hash prefixes other than "$2b$", please refer to
* the comments in BF_set_key() below and to the included crypt(3) man page.
*
* There's a paper on the algorithm that explains its design decisions:
*
* http://www.usenix.org/events/usenix99/provos.html
*
* Some of the tricks in BF_ROUND might be inspired by Eric Young's
* Blowfish library (I can't be sure if I would think of something if I
* hadn't seen his code).
*/
#include <string.h>
#include <errno.h>
#ifndef __set_errno
#define __set_errno(val) errno = (val)
#endif
/* Just to make sure the prototypes match the actual definitions */
#ifdef _WIN32 || _WIN64
#include "../include/bcrypt/crypt_blowfish.h"
#else
#include "crypt_blowfish.h"
#endif
#ifdef __i386__
#define BF_ASM 1
#define BF_SCALE 1
#elif defined(__x86_64__) || defined(__alpha__) || defined(__hppa__)
#define BF_ASM 0
#define BF_SCALE 1
#else
#define BF_ASM 0
#define BF_SCALE 0
#endif
typedef unsigned int BF_word;
typedef signed int BF_word_signed;
/* Number of Blowfish rounds, this is also hardcoded into a few places */
#define BF_N 16
typedef BF_word BF_key[BF_N + 2];
typedef struct {
BF_word S[4][0x100];
BF_key P;
} BF_ctx;
/*
* Magic IV for 64 Blowfish encryptions that we do at the end.
* The string is "OrpheanBeholderScryDoubt" on big-endian.
*/
static BF_word BF_magic_w[6] = {
0x4F727068, 0x65616E42, 0x65686F6C,
0x64657253, 0x63727944, 0x6F756274
};
/*
* P-box and S-box tables initialized with digits of Pi.
*/
static BF_ctx BF_init_state = {
{
{
0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7,
0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee,
0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef,
0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce,
0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e,
0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88,
0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e,
0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88,
0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6,
0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba,
0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f,
0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279,
0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab,
0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0,
0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790,
0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7,
0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad,
0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477,
0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49,
0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41,
0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400,
0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a
}, {
0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623,
0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6,
0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e,
0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff,
0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701,
0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf,
0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e,
0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16,
0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b,
0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f,
0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4,
0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802,
0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510,
0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50,
0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8,
0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128,
0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0,
0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3,
0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00,
0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735,
0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9,
0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7
}, {
0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934,
0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45,
0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a,
0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42,
0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2,
0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33,
0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3,
0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b,
0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922,
0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37,
0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804,
0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d,
0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350,
0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d,
0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f,
0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2,
0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e,
0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52,
0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5,
0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24,
0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4,
0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0
}, {
0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b,
0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8,
0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304,
0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9,
0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593,
0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b,
0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c,
0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb,
0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991,
0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae,
0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5,
0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84,
0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8,
0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38,
0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c,
0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964,
0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8,
0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02,
0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614,
0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0,
0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e,
0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
}
}, {
0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344,
0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,
0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,
0x9216d5d9, 0x8979fb1b
}
};
static unsigned char BF_itoa64[64 + 1] =
"./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
static unsigned char BF_atoi64[0x60] = {
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 1,
54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 64, 64, 64, 64, 64,
64, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 64, 64, 64, 64, 64,
64, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 64, 64, 64, 64, 64
};
#define BF_safe_atoi64(dst, src) \
{ \
tmp = (unsigned char)(src); \
if ((unsigned int)(tmp -= 0x20) >= 0x60) return -1; \
tmp = BF_atoi64[tmp]; \
if (tmp > 63) return -1; \
(dst) = tmp; \
}
static int BF_decode(BF_word *dst, const char *src, int size)
{
unsigned char *dptr = (unsigned char *)dst;
unsigned char *end = dptr + size;
const unsigned char *sptr = (const unsigned char *)src;
unsigned int tmp, c1, c2, c3, c4;
do {
BF_safe_atoi64(c1, *sptr++);
BF_safe_atoi64(c2, *sptr++);
*dptr++ = (c1 << 2) | ((c2 & 0x30) >> 4);
if (dptr >= end) break;
BF_safe_atoi64(c3, *sptr++);
*dptr++ = ((c2 & 0x0F) << 4) | ((c3 & 0x3C) >> 2);
if (dptr >= end) break;
BF_safe_atoi64(c4, *sptr++);
*dptr++ = ((c3 & 0x03) << 6) | c4;
} while (dptr < end);
return 0;
}
static void BF_encode(char *dst, const BF_word *src, int size)
{
const unsigned char *sptr = (const unsigned char *)src;
const unsigned char *end = sptr + size;
unsigned char *dptr = (unsigned char *)dst;
unsigned int c1, c2;
do {
c1 = *sptr++;
*dptr++ = BF_itoa64[c1 >> 2];
c1 = (c1 & 0x03) << 4;
if (sptr >= end) {
*dptr++ = BF_itoa64[c1];
break;
}
c2 = *sptr++;
c1 |= c2 >> 4;
*dptr++ = BF_itoa64[c1];
c1 = (c2 & 0x0f) << 2;
if (sptr >= end) {
*dptr++ = BF_itoa64[c1];
break;
}
c2 = *sptr++;
c1 |= c2 >> 6;
*dptr++ = BF_itoa64[c1];
*dptr++ = BF_itoa64[c2 & 0x3f];
} while (sptr < end);
}
static void BF_swap(BF_word *x, int count)
{
static int endianness_check = 1;
char *is_little_endian = (char *)&endianness_check;
BF_word tmp;
if (*is_little_endian)
do {
tmp = *x;
tmp = (tmp << 16) | (tmp >> 16);
*x++ = ((tmp & 0x00FF00FF) << 8) | ((tmp >> 8) & 0x00FF00FF);
} while (--count);
}
#if BF_SCALE
/* Architectures which can shift addresses left by 2 bits with no extra cost */
#define BF_ROUND(L, R, N) \
tmp1 = L & 0xFF; \
tmp2 = L >> 8; \
tmp2 &= 0xFF; \
tmp3 = L >> 16; \
tmp3 &= 0xFF; \
tmp4 = L >> 24; \
tmp1 = data.ctx.S[3][tmp1]; \
tmp2 = data.ctx.S[2][tmp2]; \
tmp3 = data.ctx.S[1][tmp3]; \
tmp3 += data.ctx.S[0][tmp4]; \
tmp3 ^= tmp2; \
R ^= data.ctx.P[N + 1]; \
tmp3 += tmp1; \
R ^= tmp3;
#else
/* Architectures with no complicated addressing modes supported */
#define BF_INDEX(S, i) \
(*((BF_word *)(((unsigned char *)S) + (i))))
#define BF_ROUND(L, R, N) \
tmp1 = L & 0xFF; \
tmp1 <<= 2; \
tmp2 = L >> 6; \
tmp2 &= 0x3FC; \
tmp3 = L >> 14; \
tmp3 &= 0x3FC; \
tmp4 = L >> 22; \
tmp4 &= 0x3FC; \
tmp1 = BF_INDEX(data.ctx.S[3], tmp1); \
tmp2 = BF_INDEX(data.ctx.S[2], tmp2); \
tmp3 = BF_INDEX(data.ctx.S[1], tmp3); \
tmp3 += BF_INDEX(data.ctx.S[0], tmp4); \
tmp3 ^= tmp2; \
R ^= data.ctx.P[N + 1]; \
tmp3 += tmp1; \
R ^= tmp3;
#endif
/*
* Encrypt one block, BF_N is hardcoded here.
*/
#define BF_ENCRYPT \
L ^= data.ctx.P[0]; \
BF_ROUND(L, R, 0); \
BF_ROUND(R, L, 1); \
BF_ROUND(L, R, 2); \
BF_ROUND(R, L, 3); \
BF_ROUND(L, R, 4); \
BF_ROUND(R, L, 5); \
BF_ROUND(L, R, 6); \
BF_ROUND(R, L, 7); \
BF_ROUND(L, R, 8); \
BF_ROUND(R, L, 9); \
BF_ROUND(L, R, 10); \
BF_ROUND(R, L, 11); \
BF_ROUND(L, R, 12); \
BF_ROUND(R, L, 13); \
BF_ROUND(L, R, 14); \
BF_ROUND(R, L, 15); \
tmp4 = R; \
R = L; \
L = tmp4 ^ data.ctx.P[BF_N + 1];
#if BF_ASM
#define BF_body() \
_BF_body_r(&data.ctx);
#else
#define BF_body() \
L = R = 0; \
ptr = data.ctx.P; \
do { \
ptr += 2; \
BF_ENCRYPT; \
*(ptr - 2) = L; \
*(ptr - 1) = R; \
} while (ptr < &data.ctx.P[BF_N + 2]); \
\
ptr = data.ctx.S[0]; \
do { \
ptr += 2; \
BF_ENCRYPT; \
*(ptr - 2) = L; \
*(ptr - 1) = R; \
} while (ptr < &data.ctx.S[3][0xFF]);
#endif
static void BF_set_key(const char *key, BF_key expanded, BF_key initial,
unsigned char flags)
{
const char *ptr = key;
unsigned int bug, i, j;
BF_word safety, sign, diff, tmp[2];
/*
* There was a sign extension bug in older revisions of this function. While
* we would have liked to simply fix the bug and move on, we have to provide
* a backwards compatibility feature (essentially the bug) for some systems and
* a safety measure for some others. The latter is needed because for certain
* multiple inputs to the buggy algorithm there exist easily found inputs to
* the correct algorithm that produce the same hash. Thus, we optionally
* deviate from the correct algorithm just enough to avoid such collisions.
* While the bug itself affected the majority of passwords containing
* characters with the 8th bit set (although only a percentage of those in a
* collision-producing way), the anti-collision safety measure affects
* only a subset of passwords containing the '\xff' character (not even all of
* those passwords, just some of them). This character is not found in valid
* UTF-8 sequences and is rarely used in popular 8-bit character encodings.
* Thus, the safety measure is unlikely to cause much annoyance, and is a
* reasonable tradeoff to use when authenticating against existing hashes that
* are not reliably known to have been computed with the correct algorithm.
*
* We use an approach that tries to minimize side-channel leaks of password
* information - that is, we mostly use fixed-cost bitwise operations instead
* of branches or table lookups. (One conditional branch based on password
* length remains. It is not part of the bug aftermath, though, and is
* difficult and possibly unreasonable to avoid given the use of C strings by
* the caller, which results in similar timing leaks anyway.)
*
* For actual implementation, we set an array index in the variable "bug"
* (0 means no bug, 1 means sign extension bug emulation) and a flag in the
* variable "safety" (bit 16 is set when the safety measure is requested).
* Valid combinations of settings are:
*
* Prefix "$2a$": bug = 0, safety = 0x10000
* Prefix "$2b$": bug = 0, safety = 0
* Prefix "$2x$": bug = 1, safety = 0
* Prefix "$2y$": bug = 0, safety = 0
*/
bug = (unsigned int)flags & 1;
safety = ((BF_word)flags & 2) << 15;
sign = diff = 0;
for (i = 0; i < BF_N + 2; i++) {
tmp[0] = tmp[1] = 0;
for (j = 0; j < 4; j++) {
tmp[0] <<= 8;
tmp[0] |= (unsigned char)*ptr; /* correct */
tmp[1] <<= 8;
tmp[1] |= (BF_word_signed)(signed char)*ptr; /* bug */
/*
* Sign extension in the first char has no effect - nothing to overwrite yet,
* and those extra 24 bits will be fully shifted out of the 32-bit word. For
* chars 2, 3, 4 in each four-char block, we set bit 7 of "sign" if sign
* extension in tmp[1] occurs. Once this flag is set, it remains set.
*/
if (j)
sign |= tmp[1] & 0x80;
if (!*ptr)
ptr = key;
else
ptr++;
}
diff |= tmp[0] ^ tmp[1]; /* Non-zero on any differences */
expanded[i] = tmp[bug];
initial[i] = BF_init_state.P[i] ^ tmp[bug];
}
/*
* At this point, "diff" is zero iff the correct and buggy algorithms produced
* exactly the same result. If so and if "sign" is non-zero, which indicates
* that there was a non-benign sign extension, this means that we have a
* collision between the correctly computed hash for this password and a set of
* passwords that could be supplied to the buggy algorithm. Our safety measure
* is meant to protect from such many-buggy to one-correct collisions, by
* deviating from the correct algorithm in such cases. Let's check for this.
*/
diff |= diff >> 16; /* still zero iff exact match */
diff &= 0xffff; /* ditto */
diff += 0xffff; /* bit 16 set iff "diff" was non-zero (on non-match) */
sign <<= 9; /* move the non-benign sign extension flag to bit 16 */
sign &= ~diff & safety; /* action needed? */
/*
* If we have determined that we need to deviate from the correct algorithm,
* flip bit 16 in initial expanded key. (The choice of 16 is arbitrary, but
* let's stick to it now. It came out of the approach we used above, and it's
* not any worse than any other choice we could make.)
*
* It is crucial that we don't do the same to the expanded key used in the main
* Eksblowfish loop. By doing it to only one of these two, we deviate from a
* state that could be directly specified by a password to the buggy algorithm
* (and to the fully correct one as well, but that's a side-effect).
*/
initial[0] ^= sign;
}
static const unsigned char flags_by_subtype[26] =
{2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 0};
static char *BF_crypt(const char *key, const char *setting,
char *output, int size,
BF_word min)
{
#if BF_ASM
extern void _BF_body_r(BF_ctx *ctx);
#endif
struct {
BF_ctx ctx;
BF_key expanded_key;
union {
BF_word salt[4];
BF_word output[6];
} binary;
} data;
BF_word L, R;
BF_word tmp1, tmp2, tmp3, tmp4;
BF_word *ptr;
BF_word count;
int i;
if (size < 7 + 22 + 31 + 1) {
__set_errno(ERANGE);
return NULL;
}
if (setting[0] != '$' ||
setting[1] != '2' ||
setting[2] < 'a' || setting[2] > 'z' ||
!flags_by_subtype[(unsigned int)(unsigned char)setting[2] - 'a'] ||
setting[3] != '$' ||
setting[4] < '0' || setting[4] > '3' ||
setting[5] < '0' || setting[5] > '9' ||
(setting[4] == '3' && setting[5] > '1') ||
setting[6] != '$') {
__set_errno(EINVAL);
return NULL;
}
count = (BF_word)1 << ((setting[4] - '0') * 10 + (setting[5] - '0'));
if (count < min || BF_decode(data.binary.salt, &setting[7], 16)) {
__set_errno(EINVAL);
return NULL;
}
BF_swap(data.binary.salt, 4);
BF_set_key(key, data.expanded_key, data.ctx.P,
flags_by_subtype[(unsigned int)(unsigned char)setting[2] - 'a']);
memcpy(data.ctx.S, BF_init_state.S, sizeof(data.ctx.S));
L = R = 0;
for (i = 0; i < BF_N + 2; i += 2) {
L ^= data.binary.salt[i & 2];
R ^= data.binary.salt[(i & 2) + 1];
BF_ENCRYPT;
data.ctx.P[i] = L;
data.ctx.P[i + 1] = R;
}
ptr = data.ctx.S[0];
do {
ptr += 4;
L ^= data.binary.salt[(BF_N + 2) & 3];
R ^= data.binary.salt[(BF_N + 3) & 3];
BF_ENCRYPT;
*(ptr - 4) = L;
*(ptr - 3) = R;
L ^= data.binary.salt[(BF_N + 4) & 3];
R ^= data.binary.salt[(BF_N + 5) & 3];
BF_ENCRYPT;
*(ptr - 2) = L;
*(ptr - 1) = R;
} while (ptr < &data.ctx.S[3][0xFF]);
do {
int done;
for (i = 0; i < BF_N + 2; i += 2) {
data.ctx.P[i] ^= data.expanded_key[i];
data.ctx.P[i + 1] ^= data.expanded_key[i + 1];
}
done = 0;
do {
BF_body();
if (done)
break;
done = 1;
tmp1 = data.binary.salt[0];
tmp2 = data.binary.salt[1];
tmp3 = data.binary.salt[2];
tmp4 = data.binary.salt[3];
for (i = 0; i < BF_N; i += 4) {
data.ctx.P[i] ^= tmp1;
data.ctx.P[i + 1] ^= tmp2;
data.ctx.P[i + 2] ^= tmp3;
data.ctx.P[i + 3] ^= tmp4;
}
data.ctx.P[16] ^= tmp1;
data.ctx.P[17] ^= tmp2;
} while (1);
} while (--count);
for (i = 0; i < 6; i += 2) {
L = BF_magic_w[i];
R = BF_magic_w[i + 1];
count = 64;
do {
BF_ENCRYPT;
} while (--count);
data.binary.output[i] = L;
data.binary.output[i + 1] = R;
}
memcpy(output, setting, 7 + 22 - 1);
output[7 + 22 - 1] = BF_itoa64[(int)
BF_atoi64[(int)setting[7 + 22 - 1] - 0x20] & 0x30];
/* This has to be bug-compatible with the original implementation, so
* only encode 23 of the 24 bytes. :-) */
BF_swap(data.binary.output, 6);
BF_encode(&output[7 + 22], data.binary.output, 23);
output[7 + 22 + 31] = '\0';
return output;
}
int _crypt_output_magic(const char *setting, char *output, int size)
{
if (size < 3)
return -1;
output[0] = '*';
output[1] = '0';
output[2] = '\0';
if (setting[0] == '*' && setting[1] == '0')
output[1] = '1';
return 0;
}
/*
* Please preserve the runtime self-test. It serves two purposes at once:
*
* 1. We really can't afford the risk of producing incompatible hashes e.g.
* when there's something like gcc bug 26587 again, whereas an application or
* library integrating this code might not also integrate our external tests or
* it might not run them after every build. Even if it does, the miscompile
* might only occur on the production build, but not on a testing build (such
* as because of different optimization settings). It is painful to recover
* from incorrectly-computed hashes - merely fixing whatever broke is not
* enough. Thus, a proactive measure like this self-test is needed.
*
* 2. We don't want to leave sensitive data from our actual password hash
* computation on the stack or in registers. Previous revisions of the code
* would do explicit cleanups, but simply running the self-test after hash
* computation is more reliable.
*
* The performance cost of this quick self-test is around 0.6% at the "$2a$08"
* setting.
*/
char *_crypt_blowfish_rn(const char *key, const char *setting,
char *output, int size)
{
const char *test_key = "8b \xd0\xc1\xd2\xcf\xcc\xd8";
const char *test_setting = "$2a$00$abcdefghijklmnopqrstuu";
static const char * const test_hashes[2] =
{"i1D709vfamulimlGcq0qq3UvuUasvEa\0\x55", /* 'a', 'b', 'y' */
"VUrPmXD6q/nVSSp7pNDhCR9071IfIRe\0\x55"}; /* 'x' */
const char *test_hash = test_hashes[0];
char *retval;
const char *p;
int save_errno, ok;
struct {
char s[7 + 22 + 1];
char o[7 + 22 + 31 + 1 + 1 + 1];
} buf;
/* Hash the supplied password */
_crypt_output_magic(setting, output, size);
retval = BF_crypt(key, setting, output, size, 16);
save_errno = errno;
/*
* Do a quick self-test. It is important that we make both calls to BF_crypt()
* from the same scope such that they likely use the same stack locations,
* which makes the second call overwrite the first call's sensitive data on the
* stack and makes it more likely that any alignment related issues would be
* detected by the self-test.
*/
memcpy(buf.s, test_setting, sizeof(buf.s));
if (retval) {
unsigned int flags = flags_by_subtype[
(unsigned int)(unsigned char)setting[2] - 'a'];
test_hash = test_hashes[flags & 1];
buf.s[2] = setting[2];
}
memset(buf.o, 0x55, sizeof(buf.o));
buf.o[sizeof(buf.o) - 1] = 0;
p = BF_crypt(test_key, buf.s, buf.o, sizeof(buf.o) - (1 + 1), 1);
ok = (p == buf.o &&
!memcmp(p, buf.s, 7 + 22) &&
!memcmp(p + (7 + 22), test_hash, 31 + 1 + 1 + 1));
{
const char *k = "\xff\xa3" "34" "\xff\xff\xff\xa3" "345";
BF_key ae, ai, ye, yi;
BF_set_key(k, ae, ai, 2); /* $2a$ */
BF_set_key(k, ye, yi, 4); /* $2y$ */
ai[0] ^= 0x10000; /* undo the safety (for comparison) */
ok = ok && ai[0] == 0xdb9c59bc && ye[17] == 0x33343500 &&
!memcmp(ae, ye, sizeof(ae)) &&
!memcmp(ai, yi, sizeof(ai));
}
__set_errno(save_errno);
if (ok)
return retval;
/* Should not happen */
_crypt_output_magic(setting, output, size);
__set_errno(EINVAL); /* pretend we don't support this hash type */
return NULL;
}
char *_crypt_gensalt_blowfish_rn(const char *prefix, unsigned long count,
const char *input, int size, char *output, int output_size)
{
if (size < 16 || output_size < 7 + 22 + 1 ||
(count && (count < 4 || count > 31)) ||
prefix[0] != '$' || prefix[1] != '2' ||
(prefix[2] != 'a' && prefix[2] != 'b' && prefix[2] != 'y')) {
if (output_size > 0) output[0] = '\0';
__set_errno((output_size < 7 + 22 + 1) ? ERANGE : EINVAL);
return NULL;
}
if (!count) count = 5;
output[0] = '$';
output[1] = '2';
output[2] = prefix[2];
output[3] = '$';
output[4] = '0' + count / 10;
output[5] = '0' + count % 10;
output[6] = '$';
BF_encode(&output[7], (const BF_word *)input, 16);
output[7 + 22] = '\0';
return output;
}

View File

@ -0,0 +1,128 @@
/*
* Written by Solar Designer <solar at openwall.com> in 2000-2011.
* No copyright is claimed, and the software is hereby placed in the public
* domain. In case this attempt to disclaim copyright and place the software
* in the public domain is deemed null and void, then the software is
* Copyright (c) 2000-2011 Solar Designer and it is hereby released to the
* general public under the following terms:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* There's ABSOLUTELY NO WARRANTY, express or implied.
*
* See crypt_blowfish.c for more information.
*
* This file contains salt generation functions for the traditional and
* other common crypt(3) algorithms, except for bcrypt which is defined
* entirely in crypt_blowfish.c.
*/
#include <string.h>
#include <errno.h>
#ifndef __set_errno
#define __set_errno(val) errno = (val)
#endif
/* Just to make sure the prototypes match the actual definitions */
#ifdef _WIN32
#include "../include/bcrypt/crypt_gensalt.h"
#else
#include "crypt_gensalt.h"
#endif
unsigned char _crypt_itoa64[64 + 1] =
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
char *_crypt_gensalt_traditional_rn(const char *prefix, unsigned long count,
const char *input, int size, char *output, int output_size)
{
(void) prefix;
if (size < 2 || output_size < 2 + 1 || (count && count != 25)) {
if (output_size > 0) output[0] = '\0';
__set_errno((output_size < 2 + 1) ? ERANGE : EINVAL);
return NULL;
}
output[0] = _crypt_itoa64[(unsigned int)input[0] & 0x3f];
output[1] = _crypt_itoa64[(unsigned int)input[1] & 0x3f];
output[2] = '\0';
return output;
}
char *_crypt_gensalt_extended_rn(const char *prefix, unsigned long count,
const char *input, int size, char *output, int output_size)
{
unsigned long value;
(void) prefix;
/* Even iteration counts make it easier to detect weak DES keys from a look
* at the hash, so they should be avoided */
if (size < 3 || output_size < 1 + 4 + 4 + 1 ||
(count && (count > 0xffffff || !(count & 1)))) {
if (output_size > 0) output[0] = '\0';
__set_errno((output_size < 1 + 4 + 4 + 1) ? ERANGE : EINVAL);
return NULL;
}
if (!count) count = 725;
output[0] = '_';
output[1] = _crypt_itoa64[count & 0x3f];
output[2] = _crypt_itoa64[(count >> 6) & 0x3f];
output[3] = _crypt_itoa64[(count >> 12) & 0x3f];
output[4] = _crypt_itoa64[(count >> 18) & 0x3f];
value = (unsigned long)(unsigned char)input[0] |
((unsigned long)(unsigned char)input[1] << 8) |
((unsigned long)(unsigned char)input[2] << 16);
output[5] = _crypt_itoa64[value & 0x3f];
output[6] = _crypt_itoa64[(value >> 6) & 0x3f];
output[7] = _crypt_itoa64[(value >> 12) & 0x3f];
output[8] = _crypt_itoa64[(value >> 18) & 0x3f];
output[9] = '\0';
return output;
}
char *_crypt_gensalt_md5_rn(const char *prefix, unsigned long count,
const char *input, int size, char *output, int output_size)
{
unsigned long value;
(void) prefix;
if (size < 3 || output_size < 3 + 4 + 1 || (count && count != 1000)) {
if (output_size > 0) output[0] = '\0';
__set_errno((output_size < 3 + 4 + 1) ? ERANGE : EINVAL);
return NULL;
}
output[0] = '$';
output[1] = '1';
output[2] = '$';
value = (unsigned long)(unsigned char)input[0] |
((unsigned long)(unsigned char)input[1] << 8) |
((unsigned long)(unsigned char)input[2] << 16);
output[3] = _crypt_itoa64[value & 0x3f];
output[4] = _crypt_itoa64[(value >> 6) & 0x3f];
output[5] = _crypt_itoa64[(value >> 12) & 0x3f];
output[6] = _crypt_itoa64[(value >> 18) & 0x3f];
output[7] = '\0';
if (size >= 6 && output_size >= 3 + 4 + 4 + 1) {
value = (unsigned long)(unsigned char)input[3] |
((unsigned long)(unsigned char)input[4] << 8) |
((unsigned long)(unsigned char)input[5] << 16);
output[7] = _crypt_itoa64[value & 0x3f];
output[8] = _crypt_itoa64[(value >> 6) & 0x3f];
output[9] = _crypt_itoa64[(value >> 12) & 0x3f];
output[10] = _crypt_itoa64[(value >> 18) & 0x3f];
output[11] = '\0';
}
return output;
}

19
src/bcrypt/src/main.cpp Normal file
View File

@ -0,0 +1,19 @@
#include "bcrypt/BCrypt.hpp"
#include <iostream>
int main(){
std::string right_password = "right_password";
std::string wrong_password = "wrong_password";
std::cout << "generate hash... " << std::flush;
std::string hash = BCrypt::generateHash(right_password, 12);
std::cout << "done." << std::endl;
std::cout << "checking right password: " << std::flush
<< BCrypt::validatePassword(right_password,hash) << std::endl;
std::cout << "checking wrong password: " << std::flush
<< BCrypt::validatePassword(wrong_password,hash) << std::endl;
return 0;
}

563
src/bcrypt/src/wrapper.c Normal file
View File

@ -0,0 +1,563 @@
/*
* Written by Solar Designer <solar at openwall.com> in 2000-2014.
* No copyright is claimed, and the software is hereby placed in the public
* domain. In case this attempt to disclaim copyright and place the software
* in the public domain is deemed null and void, then the software is
* Copyright (c) 2000-2014 Solar Designer and it is hereby released to the
* general public under the following terms:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* There's ABSOLUTELY NO WARRANTY, express or implied.
*
* See crypt_blowfish.c for more information.
*/
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#ifndef __set_errno
#define __set_errno(val) errno = (val)
#endif
#ifdef TEST
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <sys/time.h>
#include <sys/times.h>
#ifdef TEST_THREADS
#include <pthread.h>
#endif
#endif
#define CRYPT_OUTPUT_SIZE (7 + 22 + 31 + 1)
#define CRYPT_GENSALT_OUTPUT_SIZE (7 + 22 + 1)
#if defined(__GLIBC__) && defined(_LIBC)
#define __SKIP_GNU
#endif
#ifdef _WIN32 | _WIN64
#include "../include/bcrypt/ow-crypt.h"
#include "../include/bcrypt/crypt_blowfish.h"
#include "../include/bcrypt/crypt_gensalt.h"
#else
#include "ow-crypt.h"
#include "crypt_blowfish.h"
#include "crypt_gensalt.h"
#endif
#if defined(__GLIBC__) && defined(_LIBC)
/* crypt.h from glibc-crypt-2.1 will define struct crypt_data for us */
#include "crypt.h"
extern char *__md5_crypt_r(const char *key, const char *salt,
char *buffer, int buflen);
/* crypt-entry.c needs to be patched to define __des_crypt_r rather than
* __crypt_r, and not define crypt_r and crypt at all */
extern char *__des_crypt_r(const char *key, const char *salt,
struct crypt_data *data);
extern struct crypt_data _ufc_foobar;
#endif
static int _crypt_data_alloc(void **data, int *size, int need)
{
void *updated;
if (*data && *size >= need) return 0;
updated = realloc(*data, need);
if (!updated) {
#ifndef __GLIBC__
/* realloc(3) on glibc sets errno, so we don't need to bother */
__set_errno(ENOMEM);
#endif
return -1;
}
#if defined(__GLIBC__) && defined(_LIBC)
if (need >= sizeof(struct crypt_data))
((struct crypt_data *)updated)->initialized = 0;
#endif
*data = updated;
*size = need;
return 0;
}
static char *_crypt_retval_magic(char *retval, const char *setting,
char *output, int size)
{
if (retval)
return retval;
if (_crypt_output_magic(setting, output, size))
return NULL; /* shouldn't happen */
return output;
}
#if defined(__GLIBC__) && defined(_LIBC)
/*
* Applications may re-use the same instance of struct crypt_data without
* resetting the initialized field in order to let crypt_r() skip some of
* its initialization code. Thus, it is important that our multiple hashing
* algorithms either don't conflict with each other in their use of the
* data area or reset the initialized field themselves whenever required.
* Currently, the hashing algorithms simply have no conflicts: the first
* field of struct crypt_data is the 128-byte large DES key schedule which
* __des_crypt_r() calculates each time it is called while the two other
* hashing algorithms use less than 128 bytes of the data area.
*/
char *__crypt_rn(__const char *key, __const char *setting,
void *data, int size)
{
if (setting[0] == '$' && setting[1] == '2')
return _crypt_blowfish_rn(key, setting, (char *)data, size);
if (setting[0] == '$' && setting[1] == '1')
return __md5_crypt_r(key, setting, (char *)data, size);
if (setting[0] == '$' || setting[0] == '_') {
__set_errno(EINVAL);
return NULL;
}
if (size >= sizeof(struct crypt_data))
return __des_crypt_r(key, setting, (struct crypt_data *)data);
__set_errno(ERANGE);
return NULL;
}
char *__crypt_ra(__const char *key, __const char *setting,
void **data, int *size)
{
if (setting[0] == '$' && setting[1] == '2') {
if (_crypt_data_alloc(data, size, CRYPT_OUTPUT_SIZE))
return NULL;
return _crypt_blowfish_rn(key, setting, (char *)*data, *size);
}
if (setting[0] == '$' && setting[1] == '1') {
if (_crypt_data_alloc(data, size, CRYPT_OUTPUT_SIZE))
return NULL;
return __md5_crypt_r(key, setting, (char *)*data, *size);
}
if (setting[0] == '$' || setting[0] == '_') {
__set_errno(EINVAL);
return NULL;
}
if (_crypt_data_alloc(data, size, sizeof(struct crypt_data)))
return NULL;
return __des_crypt_r(key, setting, (struct crypt_data *)*data);
}
char *__crypt_r(__const char *key, __const char *setting,
struct crypt_data *data)
{
return _crypt_retval_magic(
__crypt_rn(key, setting, data, sizeof(*data)),
setting, (char *)data, sizeof(*data));
}
char *__crypt(__const char *key, __const char *setting)
{
return _crypt_retval_magic(
__crypt_rn(key, setting, &_ufc_foobar, sizeof(_ufc_foobar)),
setting, (char *)&_ufc_foobar, sizeof(_ufc_foobar));
}
#else
char *crypt_rn(const char *key, const char *setting, void *data, int size)
{
return _crypt_blowfish_rn(key, setting, (char *)data, size);
}
char *crypt_ra(const char *key, const char *setting,
void **data, int *size)
{
if (_crypt_data_alloc(data, size, CRYPT_OUTPUT_SIZE))
return NULL;
return _crypt_blowfish_rn(key, setting, (char *)*data, *size);
}
char *crypt_r(const char *key, const char *setting, void *data)
{
return _crypt_retval_magic(
crypt_rn(key, setting, data, CRYPT_OUTPUT_SIZE),
setting, (char *)data, CRYPT_OUTPUT_SIZE);
}
char *crypt(const char *key, const char *setting)
{
static char output[CRYPT_OUTPUT_SIZE];
return _crypt_retval_magic(
crypt_rn(key, setting, output, sizeof(output)),
setting, output, sizeof(output));
}
#define __crypt_gensalt_rn crypt_gensalt_rn
#define __crypt_gensalt_ra crypt_gensalt_ra
#define __crypt_gensalt crypt_gensalt
#endif
char *__crypt_gensalt_rn(const char *prefix, unsigned long count,
const char *input, int size, char *output, int output_size)
{
char *(*use)(const char *_prefix, unsigned long _count,
const char *_input, int _size,
char *_output, int _output_size);
/* This may be supported on some platforms in the future */
if (!input) {
__set_errno(EINVAL);
return NULL;
}
if (!strncmp(prefix, "$2a$", 4) || !strncmp(prefix, "$2b$", 4) ||
!strncmp(prefix, "$2y$", 4))
use = _crypt_gensalt_blowfish_rn;
else
if (!strncmp(prefix, "$1$", 3))
use = _crypt_gensalt_md5_rn;
else
if (prefix[0] == '_')
use = _crypt_gensalt_extended_rn;
else
if (!prefix[0] ||
(prefix[0] && prefix[1] &&
memchr(_crypt_itoa64, prefix[0], 64) &&
memchr(_crypt_itoa64, prefix[1], 64)))
use = _crypt_gensalt_traditional_rn;
else {
__set_errno(EINVAL);
return NULL;
}
return use(prefix, count, input, size, output, output_size);
}
char *__crypt_gensalt_ra(const char *prefix, unsigned long count,
const char *input, int size)
{
char output[CRYPT_GENSALT_OUTPUT_SIZE];
char *retval;
retval = __crypt_gensalt_rn(prefix, count,
input, size, output, sizeof(output));
if (retval) {
#ifdef _WIN32 | _WIN64
retval = _strdup(retval);
#else
retval = strdup(retval);
#endif
#ifndef __GLIBC__
/* strdup(3) on glibc sets errno, so we don't need to bother */
if (!retval)
__set_errno(ENOMEM);
#endif
}
return retval;
}
char *__crypt_gensalt(const char *prefix, unsigned long count,
const char *input, int size)
{
static char output[CRYPT_GENSALT_OUTPUT_SIZE];
return __crypt_gensalt_rn(prefix, count,
input, size, output, sizeof(output));
}
#if defined(__GLIBC__) && defined(_LIBC)
weak_alias(__crypt_rn, crypt_rn)
weak_alias(__crypt_ra, crypt_ra)
weak_alias(__crypt_r, crypt_r)
weak_alias(__crypt, crypt)
weak_alias(__crypt_gensalt_rn, crypt_gensalt_rn)
weak_alias(__crypt_gensalt_ra, crypt_gensalt_ra)
weak_alias(__crypt_gensalt, crypt_gensalt)
weak_alias(crypt, fcrypt)
#endif
#ifdef TEST
static const char *tests[][3] = {
{"$2a$05$CCCCCCCCCCCCCCCCCCCCC.E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW",
"U*U"},
{"$2a$05$CCCCCCCCCCCCCCCCCCCCC.VGOzA784oUp/Z0DY336zx7pLYAy0lwK",
"U*U*"},
{"$2a$05$XXXXXXXXXXXXXXXXXXXXXOAcXxm9kjPGEMsLznoKqmqw7tc8WCx4a",
"U*U*U"},
{"$2a$05$abcdefghijklmnopqrstuu5s2v8.iXieOjg/.AySBTTZIIVFJeBui",
"0123456789abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
"chars after 72 are ignored"},
{"$2x$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e",
"\xa3"},
{"$2x$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e",
"\xff\xff\xa3"},
{"$2y$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e",
"\xff\xff\xa3"},
{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.nqd1wy.pTMdcvrRWxyiGL2eMz.2a85.",
"\xff\xff\xa3"},
{"$2b$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e",
"\xff\xff\xa3"},
{"$2y$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq",
"\xa3"},
{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq",
"\xa3"},
{"$2b$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq",
"\xa3"},
{"$2x$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi",
"1\xa3" "345"},
{"$2x$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi",
"\xff\xa3" "345"},
{"$2x$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi",
"\xff\xa3" "34" "\xff\xff\xff\xa3" "345"},
{"$2y$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi",
"\xff\xa3" "34" "\xff\xff\xff\xa3" "345"},
{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.ZC1JEJ8Z4gPfpe1JOr/oyPXTWl9EFd.",
"\xff\xa3" "34" "\xff\xff\xff\xa3" "345"},
{"$2y$05$/OK.fbVrR/bpIqNJ5ianF.nRht2l/HRhr6zmCp9vYUvvsqynflf9e",
"\xff\xa3" "345"},
{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.nRht2l/HRhr6zmCp9vYUvvsqynflf9e",
"\xff\xa3" "345"},
{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.6IflQkJytoRVc1yuaNtHfiuq.FRlSIS",
"\xa3" "ab"},
{"$2x$05$/OK.fbVrR/bpIqNJ5ianF.6IflQkJytoRVc1yuaNtHfiuq.FRlSIS",
"\xa3" "ab"},
{"$2y$05$/OK.fbVrR/bpIqNJ5ianF.6IflQkJytoRVc1yuaNtHfiuq.FRlSIS",
"\xa3" "ab"},
{"$2x$05$6bNw2HLQYeqHYyBfLMsv/OiwqTymGIGzFsA4hOTWebfehXHNprcAS",
"\xd1\x91"},
{"$2x$05$6bNw2HLQYeqHYyBfLMsv/O9LIGgn8OMzuDoHfof8AQimSGfcSWxnS",
"\xd0\xc1\xd2\xcf\xcc\xd8"},
{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.swQOIzjOiJ9GHEPuhEkvqrUyvWhEMx6",
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"chars after 72 are ignored as usual"},
{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.R9xrDjiycxMbQE2bp.vgqlYpW5wx2yy",
"\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55"
"\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55"
"\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55"
"\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55"
"\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55"
"\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55"},
{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.9tQZzcJfm3uj2NvJ/n5xkhpqLrMpWCe",
"\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff"
"\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff"
"\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff"
"\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff"
"\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff"
"\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff"},
{"$2a$05$CCCCCCCCCCCCCCCCCCCCC.7uG0VCzI2bS7j6ymqJi9CdcdxiRTWNy",
""},
{"*0", "", "$2a$03$CCCCCCCCCCCCCCCCCCCCC."},
{"*0", "", "$2a$32$CCCCCCCCCCCCCCCCCCCCC."},
{"*0", "", "$2c$05$CCCCCCCCCCCCCCCCCCCCC."},
{"*0", "", "$2z$05$CCCCCCCCCCCCCCCCCCCCC."},
{"*0", "", "$2`$05$CCCCCCCCCCCCCCCCCCCCC."},
{"*0", "", "$2{$05$CCCCCCCCCCCCCCCCCCCCC."},
{"*1", "", "*0"},
{NULL}
};
#define which tests[0]
static volatile sig_atomic_t running;
static void handle_timer(int signum)
{
(void) signum;
running = 0;
}
static void *run(void *arg)
{
unsigned long count = 0;
int i = 0;
void *data = NULL;
int size = 0x12345678;
do {
const char *hash = tests[i][0];
const char *key = tests[i][1];
const char *setting = tests[i][2];
if (!tests[++i][0])
i = 0;
if (setting && strlen(hash) < 30) /* not for benchmark */
continue;
if (strcmp(crypt_ra(key, hash, &data, &size), hash)) {
printf("%d: FAILED (crypt_ra/%d/%lu)\n",
(int)((char *)arg - (char *)0), i, count);
free(data);
return NULL;
}
count++;
} while (running);
free(data);
return count + (char *)0;
}
int main(void)
{
struct itimerval it;
struct tms buf;
clock_t clk_tck, start_real, start_virtual, end_real, end_virtual;
unsigned long count;
void *data;
int size;
char *setting1, *setting2;
int i;
#ifdef TEST_THREADS
pthread_t t[TEST_THREADS];
void *t_retval;
#endif
data = NULL;
size = 0x12345678;
for (i = 0; tests[i][0]; i++) {
const char *hash = tests[i][0];
const char *key = tests[i][1];
const char *setting = tests[i][2];
const char *p;
int ok = !setting || strlen(hash) >= 30;
int o_size;
char s_buf[30], o_buf[61];
if (!setting) {
memcpy(s_buf, hash, sizeof(s_buf) - 1);
s_buf[sizeof(s_buf) - 1] = 0;
setting = s_buf;
}
__set_errno(0);
p = crypt(key, setting);
if ((!ok && !errno) || strcmp(p, hash)) {
printf("FAILED (crypt/%d)\n", i);
return 1;
}
if (ok && strcmp(crypt(key, hash), hash)) {
printf("FAILED (crypt/%d)\n", i);
return 1;
}
for (o_size = -1; o_size <= (int)sizeof(o_buf); o_size++) {
int ok_n = ok && o_size == (int)sizeof(o_buf);
const char *x = "abc";
strcpy(o_buf, x);
if (o_size >= 3) {
x = "*0";
if (setting[0] == '*' && setting[1] == '0')
x = "*1";
}
__set_errno(0);
p = crypt_rn(key, setting, o_buf, o_size);
if ((ok_n && (!p || strcmp(p, hash))) ||
(!ok_n && (!errno || p || strcmp(o_buf, x)))) {
printf("FAILED (crypt_rn/%d)\n", i);
return 1;
}
}
__set_errno(0);
p = crypt_ra(key, setting, &data, &size);
if ((ok && (!p || strcmp(p, hash))) ||
(!ok && (!errno || p || strcmp((char *)data, hash)))) {
printf("FAILED (crypt_ra/%d)\n", i);
return 1;
}
}
setting1 = crypt_gensalt(which[0], 12, data, size);
if (!setting1 || strncmp(setting1, "$2a$12$", 7)) {
puts("FAILED (crypt_gensalt)\n");
return 1;
}
setting2 = crypt_gensalt_ra(setting1, 12, data, size);
if (strcmp(setting1, setting2)) {
puts("FAILED (crypt_gensalt_ra/1)\n");
return 1;
}
(*(char *)data)++;
setting1 = crypt_gensalt_ra(setting2, 12, data, size);
if (!strcmp(setting1, setting2)) {
puts("FAILED (crypt_gensalt_ra/2)\n");
return 1;
}
free(setting1);
free(setting2);
free(data);
#if defined(_SC_CLK_TCK) || !defined(CLK_TCK)
clk_tck = sysconf(_SC_CLK_TCK);
#else
clk_tck = CLK_TCK;
#endif
running = 1;
signal(SIGALRM, handle_timer);
memset(&it, 0, sizeof(it));
it.it_value.tv_sec = 5;
setitimer(ITIMER_REAL, &it, NULL);
start_real = times(&buf);
start_virtual = buf.tms_utime + buf.tms_stime;
count = (char *)run((char *)0) - (char *)0;
end_real = times(&buf);
end_virtual = buf.tms_utime + buf.tms_stime;
if (end_virtual == start_virtual) end_virtual++;
printf("%.1f c/s real, %.1f c/s virtual\n",
(float)count * clk_tck / (end_real - start_real),
(float)count * clk_tck / (end_virtual - start_virtual));
#ifdef TEST_THREADS
running = 1;
it.it_value.tv_sec = 60;
setitimer(ITIMER_REAL, &it, NULL);
start_real = times(&buf);
for (i = 0; i < TEST_THREADS; i++)
if (pthread_create(&t[i], NULL, run, i + (char *)0)) {
perror("pthread_create");
return 1;
}
for (i = 0; i < TEST_THREADS; i++) {
if (pthread_join(t[i], &t_retval)) {
perror("pthread_join");
continue;
}
if (!t_retval) continue;
count = (char *)t_retval - (char *)0;
end_real = times(&buf);
printf("%d: %.1f c/s real\n", i,
(float)count * clk_tck / (end_real - start_real));
}
#endif
return 0;
}
#endif

202
src/bcrypt/src/x86.S Normal file
View File

@ -0,0 +1,202 @@
/*
* Written by Solar Designer <solar at openwall.com> in 1998-2010.
* No copyright is claimed, and the software is hereby placed in the public
* domain. In case this attempt to disclaim copyright and place the software
* in the public domain is deemed null and void, then the software is
* Copyright (c) 1998-2010 Solar Designer and it is hereby released to the
* general public under the following terms:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* There's ABSOLUTELY NO WARRANTY, express or implied.
*
* See crypt_blowfish.c for more information.
*/
#ifdef __i386__
#if defined(__OpenBSD__) && !defined(__ELF__)
#define UNDERSCORES
#define ALIGN_LOG
#endif
#if defined(__CYGWIN32__) || defined(__MINGW32__)
#define UNDERSCORES
#endif
#ifdef __DJGPP__
#define UNDERSCORES
#define ALIGN_LOG
#endif
#ifdef UNDERSCORES
#define _BF_body_r __BF_body_r
#endif
#ifdef ALIGN_LOG
#define DO_ALIGN(log) .align (log)
#elif defined(DUMBAS)
#define DO_ALIGN(log) .align 1 << log
#else
#define DO_ALIGN(log) .align (1 << (log))
#endif
#define BF_FRAME 0x200
#define ctx %esp
#define BF_ptr (ctx)
#define S(N, r) N+BF_FRAME(ctx,r,4)
#ifdef DUMBAS
#define P(N) 0x1000+N+N+N+N+BF_FRAME(ctx)
#else
#define P(N) 0x1000+4*N+BF_FRAME(ctx)
#endif
/*
* This version of the assembly code is optimized primarily for the original
* Intel Pentium but is also careful to avoid partial register stalls on the
* Pentium Pro family of processors (tested up to Pentium III Coppermine).
*
* It is possible to do 15% faster on the Pentium Pro family and probably on
* many non-Intel x86 processors, but, unfortunately, that would make things
* twice slower for the original Pentium.
*
* An additional 2% speedup may be achieved with non-reentrant code.
*/
#define L %esi
#define R %edi
#define tmp1 %eax
#define tmp1_lo %al
#define tmp2 %ecx
#define tmp2_hi %ch
#define tmp3 %edx
#define tmp3_lo %dl
#define tmp4 %ebx
#define tmp4_hi %bh
#define tmp5 %ebp
.text
#define BF_ROUND(L, R, N) \
xorl L,tmp2; \
xorl tmp1,tmp1; \
movl tmp2,L; \
shrl $16,tmp2; \
movl L,tmp4; \
movb tmp2_hi,tmp1_lo; \
andl $0xFF,tmp2; \
movb tmp4_hi,tmp3_lo; \
andl $0xFF,tmp4; \
movl S(0,tmp1),tmp1; \
movl S(0x400,tmp2),tmp5; \
addl tmp5,tmp1; \
movl S(0x800,tmp3),tmp5; \
xorl tmp5,tmp1; \
movl S(0xC00,tmp4),tmp5; \
addl tmp1,tmp5; \
movl 4+P(N),tmp2; \
xorl tmp5,R
#define BF_ENCRYPT_START \
BF_ROUND(L, R, 0); \
BF_ROUND(R, L, 1); \
BF_ROUND(L, R, 2); \
BF_ROUND(R, L, 3); \
BF_ROUND(L, R, 4); \
BF_ROUND(R, L, 5); \
BF_ROUND(L, R, 6); \
BF_ROUND(R, L, 7); \
BF_ROUND(L, R, 8); \
BF_ROUND(R, L, 9); \
BF_ROUND(L, R, 10); \
BF_ROUND(R, L, 11); \
BF_ROUND(L, R, 12); \
BF_ROUND(R, L, 13); \
BF_ROUND(L, R, 14); \
BF_ROUND(R, L, 15); \
movl BF_ptr,tmp5; \
xorl L,tmp2; \
movl P(17),L
#define BF_ENCRYPT_END \
xorl R,L; \
movl tmp2,R
DO_ALIGN(5)
.globl _BF_body_r
_BF_body_r:
movl 4(%esp),%eax
pushl %ebp
pushl %ebx
pushl %esi
pushl %edi
subl $BF_FRAME-8,%eax
xorl L,L
cmpl %esp,%eax
ja BF_die
xchgl %eax,%esp
xorl R,R
pushl %eax
leal 0x1000+BF_FRAME-4(ctx),%eax
movl 0x1000+BF_FRAME-4(ctx),tmp2
pushl %eax
xorl tmp3,tmp3
BF_loop_P:
BF_ENCRYPT_START
addl $8,tmp5
BF_ENCRYPT_END
leal 0x1000+18*4+BF_FRAME(ctx),tmp1
movl tmp5,BF_ptr
cmpl tmp5,tmp1
movl L,-8(tmp5)
movl R,-4(tmp5)
movl P(0),tmp2
ja BF_loop_P
leal BF_FRAME(ctx),tmp5
xorl tmp3,tmp3
movl tmp5,BF_ptr
BF_loop_S:
BF_ENCRYPT_START
BF_ENCRYPT_END
movl P(0),tmp2
movl L,(tmp5)
movl R,4(tmp5)
BF_ENCRYPT_START
BF_ENCRYPT_END
movl P(0),tmp2
movl L,8(tmp5)
movl R,12(tmp5)
BF_ENCRYPT_START
BF_ENCRYPT_END
movl P(0),tmp2
movl L,16(tmp5)
movl R,20(tmp5)
BF_ENCRYPT_START
addl $32,tmp5
BF_ENCRYPT_END
leal 0x1000+BF_FRAME(ctx),tmp1
movl tmp5,BF_ptr
cmpl tmp5,tmp1
movl P(0),tmp2
movl L,-8(tmp5)
movl R,-4(tmp5)
ja BF_loop_S
movl 4(%esp),%esp
popl %edi
popl %esi
popl %ebx
popl %ebp
ret
BF_die:
/* Oops, need to re-compile with a larger BF_FRAME. */
hlt
jmp BF_die
#if defined(__ELF__) && defined(__linux__)
.section .note.GNU-stack,"",@progbits
#endif
#endif

View File

@ -0,0 +1,41 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.28307.136
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libbcrypt", "libbcrypt.vcxproj", "{D6A9A3F3-1312-4494-85B8-7CE7DD4D78F4}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "..\test\test.vcxproj", "{C6B1CF6E-88DF-4109-9EF4-06CBA5BD5B68}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{D6A9A3F3-1312-4494-85B8-7CE7DD4D78F4}.Debug|x64.ActiveCfg = Debug|x64
{D6A9A3F3-1312-4494-85B8-7CE7DD4D78F4}.Debug|x64.Build.0 = Debug|x64
{D6A9A3F3-1312-4494-85B8-7CE7DD4D78F4}.Debug|x86.ActiveCfg = Debug|Win32
{D6A9A3F3-1312-4494-85B8-7CE7DD4D78F4}.Debug|x86.Build.0 = Debug|Win32
{D6A9A3F3-1312-4494-85B8-7CE7DD4D78F4}.Release|x64.ActiveCfg = Release|x64
{D6A9A3F3-1312-4494-85B8-7CE7DD4D78F4}.Release|x64.Build.0 = Release|x64
{D6A9A3F3-1312-4494-85B8-7CE7DD4D78F4}.Release|x86.ActiveCfg = Release|Win32
{D6A9A3F3-1312-4494-85B8-7CE7DD4D78F4}.Release|x86.Build.0 = Release|Win32
{C6B1CF6E-88DF-4109-9EF4-06CBA5BD5B68}.Debug|x64.ActiveCfg = Debug|x64
{C6B1CF6E-88DF-4109-9EF4-06CBA5BD5B68}.Debug|x64.Build.0 = Debug|x64
{C6B1CF6E-88DF-4109-9EF4-06CBA5BD5B68}.Debug|x86.ActiveCfg = Debug|Win32
{C6B1CF6E-88DF-4109-9EF4-06CBA5BD5B68}.Debug|x86.Build.0 = Debug|Win32
{C6B1CF6E-88DF-4109-9EF4-06CBA5BD5B68}.Release|x64.ActiveCfg = Release|x64
{C6B1CF6E-88DF-4109-9EF4-06CBA5BD5B68}.Release|x64.Build.0 = Release|x64
{C6B1CF6E-88DF-4109-9EF4-06CBA5BD5B68}.Release|x86.ActiveCfg = Release|Win32
{C6B1CF6E-88DF-4109-9EF4-06CBA5BD5B68}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {2DB786F9-9679-4A72-A4A0-2544E42B78CB}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,135 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{D6A9A3F3-1312-4494-85B8-7CE7DD4D78F4}</ProjectGuid>
<RootNamespace>libbcrypt</RootNamespace>
<WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\src\bcrypt.c" />
<ClCompile Include="..\..\src\crypt_blowfish.c" />
<ClCompile Include="..\..\src\crypt_gensalt.c" />
<ClCompile Include="..\..\src\wrapper.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\include\bcrypt\bcrypt.h" />
<ClInclude Include="..\..\include\bcrypt\BCrypt.hpp" />
<ClInclude Include="..\..\include\bcrypt\crypt.h" />
<ClInclude Include="..\..\include\bcrypt\crypt_blowfish.h" />
<ClInclude Include="..\..\include\bcrypt\crypt_gensalt.h" />
<ClInclude Include="..\..\include\bcrypt\ow-crypt.h" />
<ClInclude Include="..\..\include\bcrypt\winbcrypt.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\src\bcrypt.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\crypt_blowfish.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\crypt_gensalt.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\wrapper.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\include\bcrypt\BCrypt.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\include\bcrypt\winbcrypt.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\include\bcrypt\bcrypt.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\include\bcrypt\crypt.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\include\bcrypt\crypt_blowfish.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\include\bcrypt\crypt_gensalt.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\include\bcrypt\ow-crypt.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -0,0 +1,22 @@
#include "../../include/bcrypt/BCrypt.hpp"
#include <iostream>
using namespace std;
int main() {
string right_password = "right_password";
string wrong_password = "wrong_password";
cout << "generate hash... " << flush;
string hash = BCrypt::generateHash(right_password, 12);
cout << "done." << endl;
cout << "checking right password: " << flush
<< BCrypt::validatePassword(right_password, hash) << endl;
cout << "checking wrong password: " << flush
<< BCrypt::validatePassword(wrong_password, hash) << endl;
system("pause");
return 0;
}

View File

@ -0,0 +1,131 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.cpp" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\libbcrypt\libbcrypt.vcxproj">
<Project>{d6a9a3f3-1312-4494-85b8-7ce7dd4d78f4}</Project>
</ProjectReference>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{C6B1CF6E-88DF-4109-9EF4-06CBA5BD5B68}</ProjectGuid>
<RootNamespace>test</RootNamespace>
<WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<AdditionalDependencies>../libbcrypt/Debug/libbcrypt.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

30
src/jwt-cpp/BaseTest.cpp Normal file
View File

@ -0,0 +1,30 @@
#include <gtest/gtest.h>
#include "include/jwt-cpp/base.h"
TEST(BaseTest, Base64Decode) {
ASSERT_EQ("1", jwt::base::decode<jwt::alphabet::base64>("MQ=="));
ASSERT_EQ("12", jwt::base::decode<jwt::alphabet::base64>("MTI="));
ASSERT_EQ("123", jwt::base::decode<jwt::alphabet::base64>("MTIz"));
ASSERT_EQ("1234", jwt::base::decode<jwt::alphabet::base64>("MTIzNA=="));
}
TEST(BaseTest, Base64DecodeURL) {
ASSERT_EQ("1", jwt::base::decode<jwt::alphabet::base64url>("MQ%3d%3d"));
ASSERT_EQ("12", jwt::base::decode<jwt::alphabet::base64url>("MTI%3d"));
ASSERT_EQ("123", jwt::base::decode<jwt::alphabet::base64url>("MTIz"));
ASSERT_EQ("1234", jwt::base::decode<jwt::alphabet::base64url>("MTIzNA%3d%3d"));
}
TEST(BaseTest, Base64Encode) {
ASSERT_EQ("MQ==", jwt::base::encode<jwt::alphabet::base64>("1"));
ASSERT_EQ("MTI=", jwt::base::encode<jwt::alphabet::base64>("12"));
ASSERT_EQ("MTIz", jwt::base::encode<jwt::alphabet::base64>("123"));
ASSERT_EQ("MTIzNA==", jwt::base::encode<jwt::alphabet::base64>("1234"));
}
TEST(BaseTest, Base64EncodeURL) {
ASSERT_EQ("MQ%3d%3d", jwt::base::encode<jwt::alphabet::base64url>("1"));
ASSERT_EQ("MTI%3d", jwt::base::encode<jwt::alphabet::base64url>("12"));
ASSERT_EQ("MTIz", jwt::base::encode<jwt::alphabet::base64url>("123"));
ASSERT_EQ("MTIzNA%3d%3d", jwt::base::encode<jwt::alphabet::base64url>("1234"));
}

33
src/jwt-cpp/ClaimTest.cpp Normal file
View File

@ -0,0 +1,33 @@
#include <gtest/gtest.h>
#include "include/jwt-cpp/jwt.h"
TEST(ClaimTest, AudienceAsString) {
std::string token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJ0ZXN0In0.WZnM3SIiSRHsbO3O7Z2bmIzTJ4EC32HRBKfLznHhrh4";
auto decoded = jwt::decode(token);
ASSERT_TRUE(decoded.has_algorithm());
ASSERT_TRUE(decoded.has_type());
ASSERT_FALSE(decoded.has_content_type());
ASSERT_FALSE(decoded.has_key_id());
ASSERT_FALSE(decoded.has_issuer());
ASSERT_FALSE(decoded.has_subject());
ASSERT_TRUE(decoded.has_audience());
ASSERT_FALSE(decoded.has_expires_at());
ASSERT_FALSE(decoded.has_not_before());
ASSERT_FALSE(decoded.has_issued_at());
ASSERT_FALSE(decoded.has_id());
ASSERT_EQ("HS256", decoded.get_algorithm());
ASSERT_EQ("JWT", decoded.get_type());
auto aud = decoded.get_audience();
ASSERT_EQ(1, aud.size());
ASSERT_EQ("test", *aud.begin());
}
TEST(ClaimTest, SetAudienceAsString) {
auto token = jwt::create()
.set_type("JWT")
.set_audience("test")
.sign(jwt::algorithm::hs256("test"));
ASSERT_EQ("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJ0ZXN0In0.ny5Fa0vzAg7tNL95KWg_ecBNd3XP3tdAzq0SFA6diY4", token);
}

2494
src/jwt-cpp/Doxyfile Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,55 @@
#include <gtest/gtest.h>
#include "include/jwt-cpp/jwt.h"
namespace {
extern std::string google_cert;
extern std::string google_cert_key;
}
TEST(HelperTest, Cert2Pubkey) {
auto key = jwt::helper::extract_pubkey_from_cert(google_cert);
ASSERT_EQ(google_cert_key, key);
}
namespace {
std::string google_cert = R"(-----BEGIN CERTIFICATE-----
MIIF8DCCBVmgAwIBAgIKYFOB9QABAACIvTANBgkqhkiG9w0BAQUFADBGMQswCQYD
VQQGEwJVUzETMBEGA1UEChMKR29vZ2xlIEluYzEiMCAGA1UEAxMZR29vZ2xlIElu
dGVybmV0IEF1dGhvcml0eTAeFw0xMzA1MjIxNTQ5MDRaFw0xMzEwMzEyMzU5NTla
MGYxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1N
b3VudGFpbiBWaWV3MRMwEQYDVQQKEwpHb29nbGUgSW5jMRUwEwYDVQQDFAwqLmdv
b2dsZS5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARmSpIUbCqhUBq1UwnR
Ai7/TNSk6W8JmasR+I0r/NLDYv5yApbAz8HXXN8hDdurMRP6Jy1Q0UIKmyls8HPH
exoCo4IECjCCBAYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAsGA1Ud
DwQEAwIHgDAdBgNVHQ4EFgQUU3jT0NVNRgU5ZinRHGrlyoGEnoYwHwYDVR0jBBgw
FoAUv8Aw6/VDET5nup6R+/xq2uNrEiQwWwYDVR0fBFQwUjBQoE6gTIZKaHR0cDov
L3d3dy5nc3RhdGljLmNvbS9Hb29nbGVJbnRlcm5ldEF1dGhvcml0eS9Hb29nbGVJ
bnRlcm5ldEF1dGhvcml0eS5jcmwwZgYIKwYBBQUHAQEEWjBYMFYGCCsGAQUFBzAC
hkpodHRwOi8vd3d3LmdzdGF0aWMuY29tL0dvb2dsZUludGVybmV0QXV0aG9yaXR5
L0dvb2dsZUludGVybmV0QXV0aG9yaXR5LmNydDAMBgNVHRMBAf8EAjAAMIICwwYD
VR0RBIICujCCAraCDCouZ29vZ2xlLmNvbYINKi5hbmRyb2lkLmNvbYIWKi5hcHBl
bmdpbmUuZ29vZ2xlLmNvbYISKi5jbG91ZC5nb29nbGUuY29tghYqLmdvb2dsZS1h
bmFseXRpY3MuY29tggsqLmdvb2dsZS5jYYILKi5nb29nbGUuY2yCDiouZ29vZ2xl
LmNvLmlugg4qLmdvb2dsZS5jby5qcIIOKi5nb29nbGUuY28udWuCDyouZ29vZ2xl
LmNvbS5hcoIPKi5nb29nbGUuY29tLmF1gg8qLmdvb2dsZS5jb20uYnKCDyouZ29v
Z2xlLmNvbS5jb4IPKi5nb29nbGUuY29tLm14gg8qLmdvb2dsZS5jb20udHKCDyou
Z29vZ2xlLmNvbS52boILKi5nb29nbGUuZGWCCyouZ29vZ2xlLmVzggsqLmdvb2ds
ZS5mcoILKi5nb29nbGUuaHWCCyouZ29vZ2xlLml0ggsqLmdvb2dsZS5ubIILKi5n
b29nbGUucGyCCyouZ29vZ2xlLnB0gg8qLmdvb2dsZWFwaXMuY26CFCouZ29vZ2xl
Y29tbWVyY2UuY29tgg0qLmdzdGF0aWMuY29tggwqLnVyY2hpbi5jb22CECoudXJs
Lmdvb2dsZS5jb22CFioueW91dHViZS1ub2Nvb2tpZS5jb22CDSoueW91dHViZS5j
b22CFioueW91dHViZWVkdWNhdGlvbi5jb22CCyoueXRpbWcuY29tggthbmRyb2lk
LmNvbYIEZy5jb4IGZ29vLmdsghRnb29nbGUtYW5hbHl0aWNzLmNvbYIKZ29vZ2xl
LmNvbYISZ29vZ2xlY29tbWVyY2UuY29tggp1cmNoaW4uY29tggh5b3V0dS5iZYIL
eW91dHViZS5jb22CFHlvdXR1YmVlZHVjYXRpb24uY29tMA0GCSqGSIb3DQEBBQUA
A4GBAAMn0K3j3yhC+X+uyh6eABa2Eq7xiY5/mUB886Ir19vxluSMNKD6n/iY8vHj
trn0BhuW8/vmJyudFkIcEDUYE4ivQMlsfIL7SOGw6OevVLmm02aiRHWj5T20Ds+S
OpueYUG3NBcHP/5IzhUYIQJbGzlQaUaZBMaQeC8ZslMNLWI2
-----END CERTIFICATE-----)";
std::string google_cert_key = R"(-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZkqSFGwqoVAatVMJ0QIu/0zUpOlv
CZmrEfiNK/zSw2L+cgKWwM/B11zfIQ3bqzET+ictUNFCCpspbPBzx3saAg==
-----END PUBLIC KEY-----
)";
}

21
src/jwt-cpp/LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 Dominik Thalhammer
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

98
src/jwt-cpp/README.md Normal file
View File

@ -0,0 +1,98 @@
# jwt-cpp
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/5f7055e294744901991fd0a1620b231d)](https://app.codacy.com/app/Thalhammer/jwt-cpp?utm_source=github.com&utm_medium=referral&utm_content=Thalhammer/jwt-cpp&utm_campaign=Badge_Grade_Settings)
A header only library for creating and validating json web tokens in c++.
## Signature algorithms
As of version 0.2.0 jwt-cpp supports all algorithms defined by the spec. The modular design of jwt-cpp allows one to add additional algorithms without any problems. If you need any feel free to open a pull request.
For the sake of completeness, here is a list of all supported algorithms:
* HS256
* HS384
* HS512
* RS256
* RS384
* RS512
* ES256
* ES384
* ES512
* PS256
* PS384
* PS512
## Examples
Simple example of decoding a token and printing all claims:
```c++
#include <jwt-cpp/jwt.h>
#include <iostream>
int main(int argc, const char** argv) {
std::string token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE";
auto decoded = jwt::decode(token);
for(auto& e : decoded.get_payload_claims())
std::cout << e.first << " = " << e.second.to_json() << std::endl;
}
```
In order to verify a token you first build a verifier and use it to verify a decoded token.
```c++
auto verifier = jwt::verify()
.allow_algorithm(jwt::algorithm::hs256{ "secret" })
.with_issuer("auth0");
verifier.verify(decoded_token);
```
The created verifier is stateless so you can reuse it for different tokens.
Creating a token (and signing) is equally easy.
```c++
auto token = jwt::create()
.set_issuer("auth0")
.set_type("JWS")
.set_payload_claim("sample", std::string("test"))
.sign(jwt::algorithm::hs256{"secret"});
```
Here is a simple example of creating a token that will expire in 2 hours:
```c++
// Note to @Thalhammer: please replace with a better example if this is not a good way
auto token = jwt::create()
.set_issuer("auth0")
.set_issued_at(jwt::date(std::chrono::system_clock::now()))
.set_expires_at(jwt::date(std::chrono::system_clock::now()+ std::chrono::seconds{3600}))
.sign(jwt::algorithm::hs256{"secret"}
```
## Contributing
If you have an improvement or found a bug feel free to [open an issue](https://github.com/Thalhammer/jwt-cpp/issues/new) or add the change and create a pull request. If you file a bug please make sure to include as much information about your environment (compiler version, etc.) as possible to help reproduce the issue. If you add a new feature please make sure to also include test cases for it.
## Dependencies
In order to use jwt-cpp you need the following tools.
* libcrypto (openssl or compatible)
* libssl-dev (for the header files)
* a compiler supporting at least c++11
* basic stl support
In order to build the test cases you also need
* gtest installed in linker path
* pthread
## Troubleshooting
#### Expired tokens
If you are generating tokens that seem to immediately expire, you are likely not using UTC. Specifically,
if you use `get_time` to get the current time, it likely uses localtime, while this library uses UTC, which may be why your token is immediately expiring. Please see example above on the right way to use current time.
#### Missing _HMAC amd _EVP_sha256 symbols on Mac
There seems to exists a problem with the included openssl library of MacOS. Make sure you link to one provided by brew.
See [here](https://github.com/Thalhammer/jwt-cpp/issues/6) for more details.
#### Building on windows fails with syntax errors
The header "Windows.h", which is often included in windowsprojects, defines macros for MIN and MAX which screw up std::numeric_limits.
See [here](https://github.com/Thalhammer/jwt-cpp/issues/5) for more details. To fix this do one of the following things:
* define NOMINMAX, which suppresses this behaviour
* include this library before you include windows.h
* place ```#undef max``` and ```#undef min``` before you include this library

7
src/jwt-cpp/TestMain.cpp Normal file
View File

@ -0,0 +1,7 @@
#include <gtest/gtest.h>
int main(int argc, char *argv[])
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@ -0,0 +1,15 @@
#include <gtest/gtest.h>
#include "include/jwt-cpp/jwt.h"
TEST(TokenFormatTest, MissingDot) {
ASSERT_THROW(jwt::decode("eyJhbGciOiJub25lIiwidHlwIjoiSldTIn0.eyJpc3MiOiJhdXRoMCJ9"), std::invalid_argument);
ASSERT_THROW(jwt::decode("eyJhbGciOiJub25lIiwidHlwIjoiSldTIn0eyJpc3MiOiJhdXRoMCJ9."), std::invalid_argument);
}
TEST(TokenFormatTest, InvalidChar) {
ASSERT_THROW(jwt::decode("eyJhbGciOiJub25lIiwidHlwIjoiSldTIn0().eyJpc3MiOiJhdXRoMCJ9."), std::runtime_error);
}
TEST(TokenFormatTest, InvalidJSON) {
ASSERT_THROW(jwt::decode("YXsiYWxnIjoibm9uZSIsInR5cCI6IkpXUyJ9YQ.eyJpc3MiOiJhdXRoMCJ9."), std::runtime_error);
}

420
src/jwt-cpp/TokenTest.cpp Normal file
View File

@ -0,0 +1,420 @@
#include <gtest/gtest.h>
#include "include/jwt-cpp/jwt.h"
namespace {
extern std::string rsa_priv_key;
extern std::string rsa_pub_key;
extern std::string rsa_pub_key_invalid;
extern std::string rsa512_priv_key;
extern std::string rsa512_pub_key;
extern std::string rsa512_pub_key_invalid;
extern std::string ecdsa_priv_key;
extern std::string ecdsa_pub_key;
extern std::string ecdsa_pub_key_invalid;
}
TEST(TokenTest, DecodeToken) {
std::string token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE";
auto decoded = jwt::decode(token);
ASSERT_TRUE(decoded.has_algorithm());
ASSERT_TRUE(decoded.has_type());
ASSERT_FALSE(decoded.has_content_type());
ASSERT_FALSE(decoded.has_key_id());
ASSERT_TRUE(decoded.has_issuer());
ASSERT_FALSE(decoded.has_subject());
ASSERT_FALSE(decoded.has_audience());
ASSERT_FALSE(decoded.has_expires_at());
ASSERT_FALSE(decoded.has_not_before());
ASSERT_FALSE(decoded.has_issued_at());
ASSERT_FALSE(decoded.has_id());
ASSERT_EQ("HS256", decoded.get_algorithm());
ASSERT_EQ("JWS", decoded.get_type());
ASSERT_EQ("auth0", decoded.get_issuer());
}
TEST(TokenTest, CreateToken) {
auto token = jwt::create()
.set_issuer("auth0")
.set_type("JWS")
.sign(jwt::algorithm::none{});
ASSERT_EQ("eyJhbGciOiJub25lIiwidHlwIjoiSldTIn0.eyJpc3MiOiJhdXRoMCJ9.", token);
}
TEST(TokenTest, CreateTokenHS256) {
auto token = jwt::create()
.set_issuer("auth0")
.set_type("JWS")
.sign(jwt::algorithm::hs256{"secret"});
ASSERT_EQ("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE", token);
}
TEST(TokenTest, CreateTokenRS256) {
auto token = jwt::create()
.set_issuer("auth0")
.set_type("JWS")
.sign(jwt::algorithm::rs256(rsa_pub_key, rsa_priv_key, "", ""));
ASSERT_EQ(
"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.VA2i1ui1cnoD6I3wnji1WAVCf29EekysvevGrT2GXqK1dDMc8"
"HAZCTQxa1Q8NppnpYV-hlqxh-X3Bb0JOePTGzjynpNZoJh2aHZD-GKpZt7OO1Zp8AFWPZ3p8Cahq8536fD8RiBES9jRsvChZvOqA7gMcFc4"
"YD0iZhNIcI7a654u5yPYyTlf5kjR97prCf_OXWRn-bYY74zna4p_bP9oWCL4BkaoRcMxi-IR7kmVcCnvbYqyIrKloXP2qPO442RBGqU7Ov9"
"sGQxiVqtRHKXZR9RbfvjrErY1KGiCp9M5i2bsUHadZEY44FE2jiOmx-uc2z5c05CCXqVSpfCjWbh9gQ", token);
}
TEST(TokenTest, CreateTokenRS512) {
auto token = jwt::create()
.set_issuer("auth0")
.set_type("JWS")
.sign(jwt::algorithm::rs512(rsa512_pub_key, rsa512_priv_key, "", ""));
ASSERT_EQ(
"eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.GZhnjtsvBl2_KDSxg4JW6xnmNjr2mWhYSZSSQyLKvI0"
"TK86sJKchkt_HDy2IC5l5BGRhq_Xv9pHdA1umidQZG3a7gWvHsujqybCBgBraMTd1wJrCl4QxFg2RYHhHbRqb9BnPJgFD_vryd4GB"
"hfGgejPBCBlGrQtqFGFdHHOjNHY", token);
}
TEST(TokenTest, CreateTokenPS256) {
auto token = jwt::create()
.set_issuer("auth0")
.set_type("JWS")
.sign(jwt::algorithm::ps256(rsa_pub_key, rsa_priv_key, "", ""));
// TODO: Find a better way to check if generated signature is valid
// Can't do simple check for equal since pss adds random salt.
}
TEST(TokenTest, CreateTokenPS384) {
auto token = jwt::create()
.set_issuer("auth0")
.set_type("JWS")
.sign(jwt::algorithm::ps384(rsa_pub_key, rsa_priv_key, "", ""));
// TODO: Find a better way to check if generated signature is valid
// Can't do simple check for equal since pss adds random salt.
}
TEST(TokenTest, CreateTokenPS512) {
auto token = jwt::create()
.set_issuer("auth0")
.set_type("JWS")
.sign(jwt::algorithm::ps512(rsa_pub_key, rsa_priv_key, "", ""));
// TODO: Find a better way to check if generated signature is valid
// Can't do simple check for equal since pss adds random salt.
}
TEST(TokenTest, CreateTokenES256) {
auto token = jwt::create()
.set_issuer("auth0")
.set_type("JWS")
.sign(jwt::algorithm::es256("", ecdsa_priv_key, "", ""));
auto decoded = jwt::decode(token);
ASSERT_THROW(jwt::verify().allow_algorithm(jwt::algorithm::es256(ecdsa_pub_key_invalid, "", "", "")).verify(decoded), jwt::signature_verification_exception);
ASSERT_NO_THROW(jwt::verify().allow_algorithm(jwt::algorithm::es256(ecdsa_pub_key, "", "", "")).verify(decoded));
}
TEST(TokenTest, CreateTokenES256NoPrivate) {
ASSERT_THROW([](){
auto token = jwt::create()
.set_issuer("auth0")
.set_type("JWS")
.sign(jwt::algorithm::es256(ecdsa_pub_key, "", "", ""));
}(), jwt::signature_generation_exception);
}
TEST(TokenTest, VerifyTokenRS256) {
std::string token = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.VA2i1ui1cnoD6I3wnji1WAVCf29EekysvevGrT2GXqK1dDMc8"
"HAZCTQxa1Q8NppnpYV-hlqxh-X3Bb0JOePTGzjynpNZoJh2aHZD-GKpZt7OO1Zp8AFWPZ3p8Cahq8536fD8RiBES9jRsvChZvOqA7gMcFc4"
"YD0iZhNIcI7a654u5yPYyTlf5kjR97prCf_OXWRn-bYY74zna4p_bP9oWCL4BkaoRcMxi-IR7kmVcCnvbYqyIrKloXP2qPO442RBGqU7Ov9"
"sGQxiVqtRHKXZR9RbfvjrErY1KGiCp9M5i2bsUHadZEY44FE2jiOmx-uc2z5c05CCXqVSpfCjWbh9gQ";
auto verify = jwt::verify()
.allow_algorithm(jwt::algorithm::rs256(rsa_pub_key, rsa_priv_key, "", ""))
.with_issuer("auth0");
auto decoded_token = jwt::decode(token);
verify.verify(decoded_token);
}
TEST(TokenTest, VerifyTokenRS256PublicOnly) {
std::string token = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.VA2i1ui1cnoD6I3wnji1WAVCf29EekysvevGrT2GXqK1dDMc8"
"HAZCTQxa1Q8NppnpYV-hlqxh-X3Bb0JOePTGzjynpNZoJh2aHZD-GKpZt7OO1Zp8AFWPZ3p8Cahq8536fD8RiBES9jRsvChZvOqA7gMcFc4"
"YD0iZhNIcI7a654u5yPYyTlf5kjR97prCf_OXWRn-bYY74zna4p_bP9oWCL4BkaoRcMxi-IR7kmVcCnvbYqyIrKloXP2qPO442RBGqU7Ov9"
"sGQxiVqtRHKXZR9RbfvjrErY1KGiCp9M5i2bsUHadZEY44FE2jiOmx-uc2z5c05CCXqVSpfCjWbh9gQ";
auto verify = jwt::verify()
.allow_algorithm(jwt::algorithm::rs256(rsa_pub_key, "", "", ""))
.with_issuer("auth0");
auto decoded_token = jwt::decode(token);
verify.verify(decoded_token);
}
TEST(TokenTest, VerifyTokenRS256Fail) {
std::string token = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.VA2i1ui1cnoD6I3wnji1WAVCf29EekysvevGrT2GXqK1dDMc8"
"HAZCTQxa1Q8NppnpYV-hlqxh-X3Bb0JOePTGzjynpNZoJh2aHZD-GKpZt7OO1Zp8AFWPZ3p8Cahq8536fD8RiBES9jRsvChZvOqA7gMcFc4"
"YD0iZhNIcI7a654u5yPYyTlf5kjR97prCf_OXWRn-bYY74zna4p_bP9oWCL4BkaoRcMxi-IR7kmVcCnvbYqyIrKloXP2qPO442RBGqU7Ov9"
"sGQxiVqtRHKXZR9RbfvjrErY1KGiCp9M5i2bsUHadZEY44FE2jiOmx-uc2z5c05CCXqVSpfCjWbh9gQ";
auto verify = jwt::verify()
.allow_algorithm(jwt::algorithm::rs256(rsa_pub_key_invalid, "", "", ""))
.with_issuer("auth0");
auto decoded_token = jwt::decode(token);
ASSERT_THROW(verify.verify(decoded_token), jwt::signature_verification_exception);
}
TEST(TokenTest, VerifyTokenRS512) {
std::string token = "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.GZhnjtsvBl2_KDSxg4JW6xnmNjr2mWhYSZ"
"SSQyLKvI0TK86sJKchkt_HDy2IC5l5BGRhq_Xv9pHdA1umidQZG3a7gWvHsujqybCBgBraMTd1wJrCl4QxFg2RYHhHbRqb9BnPJgFD_vryd4"
"GBhfGgejPBCBlGrQtqFGFdHHOjNHY";
auto verify = jwt::verify()
.allow_algorithm(jwt::algorithm::rs512(rsa512_pub_key, rsa512_priv_key, "", ""))
.with_issuer("auth0");
auto decoded_token = jwt::decode(token);
verify.verify(decoded_token);
}
TEST(TokenTest, VerifyTokenRS512PublicOnly) {
std::string token = "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.GZhnjtsvBl2_KDSxg4JW6xnmNjr2mWhYSZ"
"SSQyLKvI0TK86sJKchkt_HDy2IC5l5BGRhq_Xv9pHdA1umidQZG3a7gWvHsujqybCBgBraMTd1wJrCl4QxFg2RYHhHbRqb9BnPJgFD_vryd4"
"GBhfGgejPBCBlGrQtqFGFdHHOjNHY";
auto verify = jwt::verify()
.allow_algorithm(jwt::algorithm::rs512(rsa512_pub_key, "", "", ""))
.with_issuer("auth0");
auto decoded_token = jwt::decode(token);
verify.verify(decoded_token);
}
TEST(TokenTest, VerifyTokenRS512Fail) {
std::string token = "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.GZhnjtsvBl2_KDSxg4JW6xnmNjr2mWhYSZ"
"SSQyLKvI0TK86sJKchkt_HDy2IC5l5BGRhq_Xv9pHdA1umidQZG3a7gWvHsujqybCBgBraMTd1wJrCl4QxFg2RYHhHbRqb9BnPJgFD_vryd4"
"GBhfGgejPBCBlGrQtqFGFdHHOjNHY";
auto verify = jwt::verify()
.allow_algorithm(jwt::algorithm::rs512(rsa_pub_key_invalid, "", "", ""))
.with_issuer("auth0");
auto decoded_token = jwt::decode(token);
ASSERT_THROW(verify.verify(decoded_token), jwt::signature_verification_exception);
}
TEST(TokenTest, VerifyTokenHS256) {
std::string token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE";
auto verify = jwt::verify()
.allow_algorithm(jwt::algorithm::hs256{ "secret" })
.with_issuer("auth0");
auto decoded_token = jwt::decode(token);
verify.verify(decoded_token);
}
TEST(TokenTest, VerifyFail) {
auto token = jwt::create()
.set_issuer("auth0")
.set_type("JWS")
.sign(jwt::algorithm::none{});
auto decoded_token = jwt::decode(token);
{
auto verify = jwt::verify()
.allow_algorithm(jwt::algorithm::none{})
.with_issuer("auth");
ASSERT_THROW(verify.verify(decoded_token), jwt::token_verification_exception);
}
{
auto verify = jwt::verify()
.allow_algorithm(jwt::algorithm::none{})
.with_issuer("auth0")
.with_audience({ "test" });
ASSERT_THROW(verify.verify(decoded_token), jwt::token_verification_exception);
}
{
auto verify = jwt::verify()
.allow_algorithm(jwt::algorithm::none{})
.with_issuer("auth0")
.with_subject("test");
ASSERT_THROW(verify.verify(decoded_token), jwt::token_verification_exception);
}
{
auto verify = jwt::verify()
.allow_algorithm(jwt::algorithm::none{})
.with_issuer("auth0")
.with_claim("myclaim", jwt::claim(std::string("test")));
ASSERT_THROW(verify.verify(decoded_token), jwt::token_verification_exception);
}
}
TEST(TokenTest, VerifyTokenES256) {
const std::string token = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.4iVk3-Y0v4RT4_9IaQlp-8dZ_4fsTzIylgrPTDLrEvTHBTyVS3tgPbr2_IZfLETtiKRqCg0aQ5sh9eIsTTwB1g";
auto verify = jwt::verify().allow_algorithm(jwt::algorithm::es256(ecdsa_pub_key, "", "", ""));
auto decoded_token = jwt::decode(token);
verify.verify(decoded_token);
}
TEST(TokenTest, VerifyTokenES256Fail) {
const std::string token = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.4iVk3-Y0v4RT4_9IaQlp-8dZ_4fsTzIylgrPTDLrEvTHBTyVS3tgPbr2_IZfLETtiKRqCg0aQ5sh9eIsTTwB1g";
auto verify = jwt::verify()
.allow_algorithm(jwt::algorithm::es256(ecdsa_pub_key_invalid, "", "", ""));
auto decoded_token = jwt::decode(token);
ASSERT_THROW(verify.verify(decoded_token), jwt::signature_verification_exception);
}
TEST(TokenTest, VerifyTokenPS256) {
std::string token = "eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.CJ4XjVWdbV6vXGZkD4GdJbtYc80SN9cmPOqRhZBRzOyDRqTFE"
"4MsbdKyQuhAWcvuMOjn-24qOTjVMR_P_uTC1uG6WPLcucxZyLnbb56zbKnEklW2SX0mQnCGewr-93a_vDaFT6Cp45MsF_OwFPRCMaS5CJg-"
"N5KY67UrVSr3s9nkuK9ZTQkyODHfyEUh9F_FhRCATGrb5G7_qHqBYvTvaPUXqzhhpCjN855Tocg7A24Hl0yMwM-XdasucW5xNdKjG_YCkis"
"HX7ax--JiF5GNYCO61eLFteO4THUg-3Z0r4OlGqlppyWo5X5tjcxOZCvBh7WDWfkxA48KFZPRv0nlKA";
auto verify = jwt::verify()
.allow_algorithm(jwt::algorithm::ps256(rsa_pub_key, rsa_priv_key, "", ""))
.with_issuer("auth0");
auto decoded_token = jwt::decode(token);
verify.verify(decoded_token);
}
TEST(TokenTest, VerifyTokenPS256PublicOnly) {
std::string token = "eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.CJ4XjVWdbV6vXGZkD4GdJbtYc80SN9cmPOqRhZBRzOyDRqTFE"
"4MsbdKyQuhAWcvuMOjn-24qOTjVMR_P_uTC1uG6WPLcucxZyLnbb56zbKnEklW2SX0mQnCGewr-93a_vDaFT6Cp45MsF_OwFPRCMaS5CJg-"
"N5KY67UrVSr3s9nkuK9ZTQkyODHfyEUh9F_FhRCATGrb5G7_qHqBYvTvaPUXqzhhpCjN855Tocg7A24Hl0yMwM-XdasucW5xNdKjG_YCkis"
"HX7ax--JiF5GNYCO61eLFteO4THUg-3Z0r4OlGqlppyWo5X5tjcxOZCvBh7WDWfkxA48KFZPRv0nlKA";
auto verify = jwt::verify()
.allow_algorithm(jwt::algorithm::ps256(rsa_pub_key, "", "", ""))
.with_issuer("auth0");
auto decoded_token = jwt::decode(token);
verify.verify(decoded_token);
}
TEST(TokenTest, VerifyTokenPS256Fail) {
std::string token = "eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.CJ4XjVWdbV6vXGZkD4GdJbtYc80SN9cmPOqRhZBRzOyDRqTFE"
"4MsbdKyQuhAWcvuMOjn-24qOTjVMR_P_uTC1uG6WPLcucxZyLnbb56zbKnEklW2SX0mQnCGewr-93a_vDaFT6Cp45MsF_OwFPRCMaS5CJg-"
"N5KY67UrVSr3s9nkuK9ZTQkyODHfyEUh9F_FhRCATGrb5G7_qHqBYvTvaPUXqzhhpCjN855Tocg7A24Hl0yMwM-XdasucW5xNdKjG_YCkis"
"HX7ax--JiF5GNYCO61eLFteO4THUg-3Z0r4OlGqlppyWo5X5tjcxOZCvBh7WDWfkxA48KFZPRv0nlKA";
auto verify = jwt::verify()
.allow_algorithm(jwt::algorithm::ps256(rsa_pub_key_invalid, "", "", ""))
.with_issuer("auth0");
auto decoded_token = jwt::decode(token);
ASSERT_THROW(verify.verify(decoded_token), jwt::signature_verification_exception);
}
namespace {
std::string rsa_priv_key = R"(-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC4ZtdaIrd1BPIJ
tfnF0TjIK5inQAXZ3XlCrUlJdP+XHwIRxdv1FsN12XyMYO/6ymLmo9ryoQeIrsXB
XYqlET3zfAY+diwCb0HEsVvhisthwMU4gZQu6TYW2s9LnXZB5rVtcBK69hcSlA2k
ZudMZWxZcj0L7KMfO2rIvaHw/qaVOE9j0T257Z8Kp2CLF9MUgX0ObhIsdumFRLaL
DvDUmBPr2zuh/34j2XmWwn1yjN/WvGtdfhXW79Ki1S40HcWnygHgLV8sESFKUxxQ
mKvPUTwDOIwLFL5WtE8Mz7N++kgmDcmWMCHc8kcOIu73Ta/3D4imW7VbKgHZo9+K
3ESFE3RjAgMBAAECggEBAJTEIyjMqUT24G2FKiS1TiHvShBkTlQdoR5xvpZMlYbN
tVWxUmrAGqCQ/TIjYnfpnzCDMLhdwT48Ab6mQJw69MfiXwc1PvwX1e9hRscGul36
ryGPKIVQEBsQG/zc4/L2tZe8ut+qeaK7XuYrPp8bk/X1e9qK5m7j+JpKosNSLgJj
NIbYsBkG2Mlq671irKYj2hVZeaBQmWmZxK4fw0Istz2WfN5nUKUeJhTwpR+JLUg4
ELYYoB7EO0Cej9UBG30hbgu4RyXA+VbptJ+H042K5QJROUbtnLWuuWosZ5ATldwO
u03dIXL0SH0ao5NcWBzxU4F2sBXZRGP2x/jiSLHcqoECgYEA4qD7mXQpu1b8XO8U
6abpKloJCatSAHzjgdR2eRDRx5PMvloipfwqA77pnbjTUFajqWQgOXsDTCjcdQui
wf5XAaWu+TeAVTytLQbSiTsBhrnoqVrr3RoyDQmdnwHT8aCMouOgcC5thP9vQ8Us
rVdjvRRbnJpg3BeSNimH+u9AHgsCgYEA0EzcbOltCWPHRAY7B3Ge/AKBjBQr86Kv
TdpTlxePBDVIlH+BM6oct2gaSZZoHbqPjbq5v7yf0fKVcXE4bSVgqfDJ/sZQu9Lp
PTeV7wkk0OsAMKk7QukEpPno5q6tOTNnFecpUhVLLlqbfqkB2baYYwLJR3IRzboJ
FQbLY93E8gkCgYB+zlC5VlQbbNqcLXJoImqItgQkkuW5PCgYdwcrSov2ve5r/Acz
FNt1aRdSlx4176R3nXyibQA1Vw+ztiUFowiP9WLoM3PtPZwwe4bGHmwGNHPIfwVG
m+exf9XgKKespYbLhc45tuC08DATnXoYK7O1EnUINSFJRS8cezSI5eHcbQKBgQDC
PgqHXZ2aVftqCc1eAaxaIRQhRmY+CgUjumaczRFGwVFveP9I6Gdi+Kca3DE3F9Pq
PKgejo0SwP5vDT+rOGHN14bmGJUMsX9i4MTmZUZ5s8s3lXh3ysfT+GAhTd6nKrIE
kM3Nh6HWFhROptfc6BNusRh1kX/cspDplK5x8EpJ0QKBgQDWFg6S2je0KtbV5PYe
RultUEe2C0jYMDQx+JYxbPmtcopvZQrFEur3WKVuLy5UAy7EBvwMnZwIG7OOohJb
vkSpADK6VPn9lbqq7O8cTedEHttm6otmLt8ZyEl3hZMaL3hbuRj6ysjmoFKx6CrX
rK0/Ikt5ybqUzKCMJZg2VKGTxg==
-----END PRIVATE KEY-----)";
std::string rsa_pub_key = R"(-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuGbXWiK3dQTyCbX5xdE4
yCuYp0AF2d15Qq1JSXT/lx8CEcXb9RbDddl8jGDv+spi5qPa8qEHiK7FwV2KpRE9
83wGPnYsAm9BxLFb4YrLYcDFOIGULuk2FtrPS512Qea1bXASuvYXEpQNpGbnTGVs
WXI9C+yjHztqyL2h8P6mlThPY9E9ue2fCqdgixfTFIF9Dm4SLHbphUS2iw7w1JgT
69s7of9+I9l5lsJ9cozf1rxrXX4V1u/SotUuNB3Fp8oB4C1fLBEhSlMcUJirz1E8
AziMCxS+VrRPDM+zfvpIJg3JljAh3PJHDiLu902v9w+Iplu1WyoB2aPfitxEhRN0
YwIDAQAB
-----END PUBLIC KEY-----)";
std::string rsa_pub_key_invalid = R"(-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxzYuc22QSst/dS7geYYK
5l5kLxU0tayNdixkEQ17ix+CUcUbKIsnyftZxaCYT46rQtXgCaYRdJcbB3hmyrOa
vkhTpX79xJZnQmfuamMbZBqitvscxW9zRR9tBUL6vdi/0rpoUwPMEh8+Bw7CgYR0
FK0DhWYBNDfe9HKcyZEv3max8Cdq18htxjEsdYO0iwzhtKRXomBWTdhD5ykd/fAC
VTr4+KEY+IeLvubHVmLUhbE5NgWXxrRpGasDqzKhCTmsa2Ysf712rl57SlH0Wz/M
r3F7aM9YpErzeYLrl0GhQr9BVJxOvXcVd4kmY+XkiCcrkyS1cnghnllh+LCwQu1s
YwIDAQAB
-----END PUBLIC KEY-----)";
std::string rsa512_priv_key = R"(-----BEGIN RSA PRIVATE KEY-----
MIICWwIBAAKBgQDdlatRjRjogo3WojgGHFHYLugdUWAY9iR3fy4arWNA1KoS8kVw
33cJibXr8bvwUAUparCwlvdbH6dvEOfou0/gCFQsHUfQrSDv+MuSUMAe8jzKE4qW
+jK+xQU9a03GUnKHkkle+Q0pX/g6jXZ7r1/xAK5Do2kQ+X5xK9cipRgEKwIDAQAB
AoGAD+onAtVye4ic7VR7V50DF9bOnwRwNXrARcDhq9LWNRrRGElESYYTQ6EbatXS
3MCyjjX2eMhu/aF5YhXBwkppwxg+EOmXeh+MzL7Zh284OuPbkglAaGhV9bb6/5Cp
uGb1esyPbYW+Ty2PC0GSZfIXkXs76jXAu9TOBvD0ybc2YlkCQQDywg2R/7t3Q2OE
2+yo382CLJdrlSLVROWKwb4tb2PjhY4XAwV8d1vy0RenxTB+K5Mu57uVSTHtrMK0
GAtFr833AkEA6avx20OHo61Yela/4k5kQDtjEf1N0LfI+BcWZtxsS3jDM3i1Hp0K
Su5rsCPb8acJo5RO26gGVrfAsDcIXKC+bQJAZZ2XIpsitLyPpuiMOvBbzPavd4gY
6Z8KWrfYzJoI/Q9FuBo6rKwl4BFoToD7WIUS+hpkagwWiz+6zLoX1dbOZwJACmH5
fSSjAkLRi54PKJ8TFUeOP15h9sQzydI8zJU+upvDEKZsZc/UhT/SySDOxQ4G/523
Y0sz/OZtSWcol/UMgQJALesy++GdvoIDLfJX5GBQpuFgFenRiRDabxrE9MNUZ2aP
FaFp+DyAe+b4nDwuJaW2LURbr8AEZga7oQj0uYxcYw==
-----END RSA PRIVATE KEY-----)";
std::string rsa512_pub_key = R"(-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdlatRjRjogo3WojgGHFHYLugd
UWAY9iR3fy4arWNA1KoS8kVw33cJibXr8bvwUAUparCwlvdbH6dvEOfou0/gCFQs
HUfQrSDv+MuSUMAe8jzKE4qW+jK+xQU9a03GUnKHkkle+Q0pX/g6jXZ7r1/xAK5D
o2kQ+X5xK9cipRgEKwIDAQAB
-----END PUBLIC KEY-----)";
std::string rsa512_pub_key_invalid = R"(-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxzYuc22QSst/dS7geYYK
5l5kLxU0tayNdixkEQ17ix+CUcUbKIsnyftZxaCYT46rQtXgCaYRdJcbB3hmyrOa
vkhTpX79xJZnQmfuamMbZBqitvscxW9zRR9tBUL6vdi/0rpoUwPMEh8+Bw7CgYR0
FK0DhWYBNDfe9HKcyZEv3max8Cdq18htxjEsdYO0iwzhtKRXomBWTdhD5ykd/fAC
VTr4+KEY+IeLvubHVmLUhbE5NgWXxrRpGasDqzKhCTmsa2Ysf712rl57SlH0Wz/M
r3F7aM9YpErzeYLrl0GhQr9BVJxOvXcVd4kmY+XkiCcrkyS1cnghnllh+LCwQu1s
YwIDAQAB
-----END PUBLIC KEY-----)";
std::string ecdsa_priv_key = R"(-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgPGJGAm4X1fvBuC1z
SpO/4Izx6PXfNMaiKaS5RUkFqEGhRANCAARCBvmeksd3QGTrVs2eMrrfa7CYF+sX
sjyGg+Bo5mPKGH4Gs8M7oIvoP9pb/I85tdebtKlmiCZHAZE5w4DfJSV6
-----END PRIVATE KEY-----)";
std::string ecdsa_pub_key = R"(-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEQgb5npLHd0Bk61bNnjK632uwmBfr
F7I8hoPgaOZjyhh+BrPDO6CL6D/aW/yPObXXm7SpZogmRwGROcOA3yUleg==
-----END PUBLIC KEY-----)";
std::string ecdsa_pub_key_invalid = R"(-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEoBUyo8CQAFPeYPvv78ylh5MwFZjT
CLQeb042TjiMJxG+9DLFmRSMlBQ9T/RsLLc+PmpB1+7yPAR+oR5gZn3kJQ==
-----END PUBLIC KEY-----)";
}

View File

@ -0,0 +1,168 @@
#pragma once
#include <string>
#include <array>
namespace jwt {
namespace alphabet {
struct base64 {
static const std::array<char, 64>& data() {
static std::array<char, 64> data = {
{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'}};
return data;
};
static const std::string& fill() {
static std::string fill = "=";
return fill;
}
};
struct base64url {
static const std::array<char, 64>& data() {
static std::array<char, 64> data = {
{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'}};
return data;
};
static const std::string& fill() {
static std::string fill = "%3d";
return fill;
}
};
}
class base {
public:
template<typename T>
static std::string encode(const std::string& bin) {
return encode(bin, T::data(), T::fill());
}
template<typename T>
static std::string decode(const std::string& base) {
return decode(base, T::data(), T::fill());
}
private:
static std::string encode(const std::string& bin, const std::array<char, 64>& alphabet, const std::string& fill) {
size_t size = bin.size();
std::string res;
// clear incomplete bytes
size_t fast_size = size - size % 3;
for (size_t i = 0; i < fast_size;) {
uint32_t octet_a = (unsigned char)bin[i++];
uint32_t octet_b = (unsigned char)bin[i++];
uint32_t octet_c = (unsigned char)bin[i++];
uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
res += alphabet[(triple >> 3 * 6) & 0x3F];
res += alphabet[(triple >> 2 * 6) & 0x3F];
res += alphabet[(triple >> 1 * 6) & 0x3F];
res += alphabet[(triple >> 0 * 6) & 0x3F];
}
if (fast_size == size)
return res;
size_t mod = size % 3;
uint32_t octet_a = fast_size < size ? (unsigned char)bin[fast_size++] : 0;
uint32_t octet_b = fast_size < size ? (unsigned char)bin[fast_size++] : 0;
uint32_t octet_c = fast_size < size ? (unsigned char)bin[fast_size++] : 0;
uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
switch (mod) {
case 1:
res += alphabet[(triple >> 3 * 6) & 0x3F];
res += alphabet[(triple >> 2 * 6) & 0x3F];
res += fill;
res += fill;
break;
case 2:
res += alphabet[(triple >> 3 * 6) & 0x3F];
res += alphabet[(triple >> 2 * 6) & 0x3F];
res += alphabet[(triple >> 1 * 6) & 0x3F];
res += fill;
break;
default:
break;
}
return res;
}
static std::string decode(const std::string& base, const std::array<char, 64>& alphabet, const std::string& fill) {
size_t size = base.size();
size_t fill_cnt = 0;
while (size > fill.size()) {
if (base.substr(size - fill.size(), fill.size()) == fill) {
fill_cnt++;
size -= fill.size();
if(fill_cnt > 2)
throw std::runtime_error("Invalid input");
}
else break;
}
if ((size + fill_cnt) % 4 != 0)
throw std::runtime_error("Invalid input");
size_t out_size = size / 4 * 3;
std::string res;
res.reserve(out_size);
auto get_sextet = [&](size_t offset) {
for (size_t i = 0; i < alphabet.size(); i++) {
if (alphabet[i] == base[offset])
return i;
}
throw std::runtime_error("Invalid input");
};
size_t fast_size = size - size % 4;
for (size_t i = 0; i < fast_size;) {
uint32_t sextet_a = get_sextet(i++);
uint32_t sextet_b = get_sextet(i++);
uint32_t sextet_c = get_sextet(i++);
uint32_t sextet_d = get_sextet(i++);
uint32_t triple = (sextet_a << 3 * 6)
+ (sextet_b << 2 * 6)
+ (sextet_c << 1 * 6)
+ (sextet_d << 0 * 6);
res += (triple >> 2 * 8) & 0xFF;
res += (triple >> 1 * 8) & 0xFF;
res += (triple >> 0 * 8) & 0xFF;
}
if (fill_cnt == 0)
return res;
uint32_t triple = (get_sextet(fast_size) << 3 * 6)
+ (get_sextet(fast_size + 1) << 2 * 6);
switch (fill_cnt) {
case 1:
triple |= (get_sextet(fast_size + 2) << 1 * 6);
res += (triple >> 2 * 8) & 0xFF;
res += (triple >> 1 * 8) & 0xFF;
break;
case 2:
res += (triple >> 2 * 8) & 0xFF;
break;
default:
break;
}
return res;
}
};
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

28
src/jwt-cpp/jwt-cpp.sln Normal file
View File

@ -0,0 +1,28 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jwt-cpp", "jwt-cpp.vcxproj", "{1CA8C676-7F8E-434C-9069-8F20A562E6E9}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1CA8C676-7F8E-434C-9069-8F20A562E6E9}.Debug|x64.ActiveCfg = Debug|x64
{1CA8C676-7F8E-434C-9069-8F20A562E6E9}.Debug|x64.Build.0 = Debug|x64
{1CA8C676-7F8E-434C-9069-8F20A562E6E9}.Debug|x86.ActiveCfg = Debug|Win32
{1CA8C676-7F8E-434C-9069-8F20A562E6E9}.Debug|x86.Build.0 = Debug|Win32
{1CA8C676-7F8E-434C-9069-8F20A562E6E9}.Release|x64.ActiveCfg = Release|x64
{1CA8C676-7F8E-434C-9069-8F20A562E6E9}.Release|x64.Build.0 = Release|x64
{1CA8C676-7F8E-434C-9069-8F20A562E6E9}.Release|x86.ActiveCfg = Release|Win32
{1CA8C676-7F8E-434C-9069-8F20A562E6E9}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

160
src/jwt-cpp/jwt-cpp.vcxproj Normal file
View File

@ -0,0 +1,160 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{1CA8C676-7F8E-434C-9069-8F20A562E6E9}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>jwtcpp</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>gtest.lib;gtest_main.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>gtest.lib;gtest_main.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>gtest.lib;gtest_main.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>gtest.lib;gtest_main.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="include\jwt-cpp\base.h" />
<ClInclude Include="include\jwt-cpp\jwt.h" />
<ClInclude Include="include\jwt-cpp\picojson.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="BaseTest.cpp" />
<ClCompile Include="TokenTest.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Quelldateien">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Headerdateien">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Ressourcendateien">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="include\jwt-cpp\jwt.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="include\jwt-cpp\picojson.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="include\jwt-cpp\base.h">
<Filter>Headerdateien</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="BaseTest.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="TokenTest.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -0,0 +1,3 @@
Source: jwt-cpp
Version: 2019-04-20
Description: A header only library for creating and validating json web tokens in c++

View File

@ -0,0 +1,12 @@
diff --git a/include/jwt-cpp/jwt.h b/include/jwt-cpp/jwt.h
index ec56810..a26fd97 100644
--- a/include/jwt-cpp/jwt.h
+++ b/include/jwt-cpp/jwt.h
@@ -1,6 +1,6 @@
#pragma once
#define PICOJSON_USE_INT64
-#include "picojson.h"
+#include "picojson/picojson.h"
#include "base.h"
#include <set>
#include <chrono>

View File

@ -0,0 +1,31 @@
diff --git a/include/jwt-cpp/base.h b/include/jwt-cpp/base.h
index dfca7fc..4d05c0b 100644
--- a/include/jwt-cpp/base.h
+++ b/include/jwt-cpp/base.h
@@ -2,6 +2,10 @@
#include <string>
#include <array>
+#ifdef _MSC_VER
+#pragma warning(disable : 4267)
+#endif
+
namespace jwt {
namespace alphabet {
struct base64 {
diff --git a/include/jwt-cpp/jwt.h b/include/jwt-cpp/jwt.h
index ec56810..313cef2 100644
--- a/include/jwt-cpp/jwt.h
+++ b/include/jwt-cpp/jwt.h
@@ -12,6 +12,11 @@
#include <openssl/ec.h>
#include <openssl/err.h>
+#ifdef _MSC_VER
+#pragma warning(disable : 4267)
+#pragma warning(disable : 4067)
+#endif
+
//If openssl version less than 1.1
#if OPENSSL_VERSION_NUMBER < 269484032
#define OPENSSL10

View File

@ -0,0 +1,23 @@
#header-only library
include(vcpkg_common_functions)
set(SOURCE_PATH ${CURRENT_BUILDTREES_DIR}/src/jwt-cpp)
vcpkg_from_github(OUT_SOURCE_PATH SOURCE_PATH
REPO Thalhammer/jwt-cpp
REF f0e37a79f605312686065405dd720fc197cc3df0
SHA512 ae83c205dbb340dedc58d0d3f0e2453c4edcf5ce43b401f49d02692dc8a2a4b7260f1ced05ddfa7c1d5d6f92446e232629ddbdf67a58a119b50c5c8163591598
HEAD_REF master
PATCHES fix-picojson.patch
fix-warning.patch)
# Copy the constexpr header files
file(GLOB HEADER_FILES ${SOURCE_PATH}/include/jwt-cpp/*)
file(COPY ${HEADER_FILES}
DESTINATION ${CURRENT_PACKAGES_DIR}/include/jwt-cpp
REGEX "\.(gitattributes|gitignore|picojson.h)$" EXCLUDE)
# Put the licence file where vcpkg expects it
file(COPY ${SOURCE_PATH}/LICENSE
DESTINATION ${CURRENT_PACKAGES_DIR}/share/jwt-cpp)
file(RENAME ${CURRENT_PACKAGES_DIR}/share/jwt-cpp/LICENSE ${CURRENT_PACKAGES_DIR}/share/jwt-cpp/copyright)

1
third_party/bcrypt vendored

@ -1 +0,0 @@
Subproject commit be171cd75dd65e06315a67c7dcdb8e1bbc1dabd4

1
third_party/jwt-cpp vendored

@ -1 +0,0 @@
Subproject commit bfca4f6a87bfd9d9a259939d0524169827a3a862