Compare commits

4 Commits

Author SHA1 Message Date
4f934fef35 PIHTTPClient fixes 2024-11-28 12:37:05 +03:00
3a159b0553 PIByteArray operators & | ^
PIDigest add BLAKE2 algorithms and HMAC
2024-11-27 18:27:51 +03:00
0c973f0216 add PIDigest with SHA and MD series 2024-11-27 14:40:39 +03:00
65d3168eb5 PICout::withExternalBufferAnd decomposed to PICout::withExternalBufferAndID and PICout::withExternalBufferAnd
PIString::toPercentageEncoding/fromPercentageEncoding
piStringify()
PIHTTPClient support arguments
some doc
2024-11-26 18:26:02 +03:00
36 changed files with 3622 additions and 50 deletions

View File

@@ -374,6 +374,8 @@ pip_module(main "${LIBS_MAIN}" "PIP main library" "" "" "")
generate_export_header(pip)
list(APPEND HDRS "${CMAKE_CURRENT_BINARY_DIR}/pip_export.h")
file(GLOB_RECURSE _RM_HDRS "libs/main/digest/3rd/*.h")
list(REMOVE_ITEM HDRS ${_RM_HDRS})
foreach(_m ${PIP_SRC_MODULES})
set_target_properties(pip PROPERTIES DEFINE_SYMBOL pip_${_m}_EXPORTS)
generate_export_header(pip BASE_NAME "pip_${_m}")

View File

@@ -1,54 +1,57 @@
#include "pip.h"
//! [own]
inline PICout operator <<(PICout s, const PIByteArray & ba) {
s.space(); // insert space after previous output
s.quote(); // ONLY if you want to quoted your type
inline PICout operator<<(PICout s, const PIByteArray & ba) {
s.space(); // insert space after previous output
s.quote(); // ONLY if you want to quoted your type
s.saveAndSetControls(0); // clear all features and
// save them to stack,
// now it`s behavior similar to std::cout
// your output
for (uint i = 0; i < ba.size(); ++i)
s << ba[i];
s.restoreControls(); // restore features from stack
s.quote(); // ONLY if you want to quoted your type
s.quote(); // ONLY if you want to quoted your type
return s;
}
//! [own]
// clang-format off
void _() {
//! [0]
using namespace PICoutManipulators;
int a = 10, b = 32, c = 11;
piCout << a << Hex << b << Bin << c;
// 10 20 1011
piCout << "this" << "is" << Green << "green" << Default << "word";
piCout << "this"
<< "is" << Green << "green" << Default << "word";
// this is green word
PICout(AddSpaces | AddNewLine | AddQuotes) << Tab << "tab and" << "quotes";
PICout(AddSpaces | AddNewLine | AddQuotes) << Tab << "tab and"
<< "quotes";
// "tab and" "quotes"
//! [0]
}
// clang-format on
//! [notifier]
class A: public PIObject {
PIOBJECT(A)
public:
A() {}
EVENT_HANDLER2(void, pcf, int, id, PIString*, buff) {
piCout << "PICout(" << id << ") finished:" << (*buff);
}
EVENT_HANDLER2(void, pcf, int, id, PIString *, buff) { piCout << "PICout(" << id << ") finished:" << (*buff); }
};
int main() {
A a;
CONNECTU(PICout::Notifier::object(), finished, &a, pcf);
PIString buffer = "my buff:";
PICout(&buffer, 1) << "int 10 ->" << 10 << ", time ->" << PITime::current();
int my_id = PICout::registerExternalBufferID();
PICout::withExternalBufferAndID(&buffer, my_id) << "int 10 ->" << 10 << ", time ->" << PITime::current();
return 0;
}
// PICout( 1 ) finished: my buff:int 10 -> 10 , time -> PITime(14:07:09:000)

View File

@@ -4,6 +4,7 @@
#include "pihttpclient.h"
#include "pitime.h"
#include <curl/curl.h>
CurlThreadPool::CurlThreadPool() {
piForTimes(10) {
@@ -34,6 +35,7 @@ CurlThreadPool::~CurlThreadPool() {
for (auto c: *cr)
delete c;
}
curl_global_cleanup();
}

View File

@@ -36,6 +36,16 @@ bool PIHTTPClient::init() {
if (is_cancel) return false;
PRIVATE->handle = curl_easy_init();
if (!PRIVATE->handle) return false;
auto ait = request.arguments().makeIterator();
while (ait.next()) {
if (!url.contains('?'))
url.append('?');
else
url.append('&');
url.append(ait.key().toPercentageEncoding());
url.append('=');
url.append(ait.value().toPercentageEncoding());
}
curl_easy_setopt(PRIVATE->handle, CURLOPT_WRITEDATA, this);
curl_easy_setopt(PRIVATE->handle, CURLOPT_READDATA, this);
curl_easy_setopt(PRIVATE->handle, CURLOPT_XFERINFODATA, this);
@@ -156,6 +166,7 @@ PIHTTPClient * PIHTTPClient::create(const PIString & url_, PIHTTP::Method method
PIHTTPClient * ret = new PIHTTPClient();
static_cast<PIHTTP::MessageConst &>(ret->request) = req;
ret->request.setMethod(method);
ret->reply.setMethod(method);
ret->url = url_;
return ret;
}

View File

@@ -179,7 +179,7 @@ PICout PILog::makePICout(PIObject * context, Level cat) {
if (context->name().isNotEmpty()) *buffer += " \"" + context->name() + "\"";
*buffer += "] ";
}
return PICout::withExternalBuffer(buffer, id_by_cat.value(cat), PICoutManipulators::AddSpaces);
return PICout::withExternalBufferAndID(buffer, id_by_cat.value(cat), PICoutManipulators::AddSpaces);
}

View File

@@ -208,7 +208,7 @@ PICout::~PICout() {
PICout::__mutex__().unlock();
}
if (buffer_) {
((NotifierObject *)Notifier::object())->finished(id_, buffer_);
if (id_ >= 0) ((NotifierObject *)Notifier::object())->finished(id_, buffer_);
} else {
getStdStream(stream_).flush();
}
@@ -748,7 +748,12 @@ bool PICout::isOutputDeviceActive(PICout::OutputDevice d) {
}
PICout PICout::withExternalBuffer(PIString * buffer, int id, PIFlags<PICoutManipulators::PICoutControl> controls) {
PICout PICout::withExternalBuffer(PIString * buffer, PIFlags<PICoutManipulators::PICoutControl> controls) {
return withExternalBufferAndID(buffer, -1, controls);
}
PICout PICout::withExternalBufferAndID(PIString * buffer, int id, PIFlags<PICoutManipulators::PICoutControl> controls) {
PICout c(controls);
c.buffer_ = buffer;
c.id_ = id;

View File

@@ -30,15 +30,24 @@
#ifdef DOXYGEN
//! \~english Macro used for conditional (piDebug) output to PICout
//! \~russian Макрос для условного (piDebug) вывода в PICout
//! \~english Macro used for conditional (piDebug) output to PICout(StdOut)
//! \~russian Макрос для условного (piDebug) вывода в PICout(StdOut)
# define piCout
//! \~english Macro used for conditional (piDebug) output to PICout(StdErr)
//! \~russian Макрос для условного (piDebug) вывода в PICout(StdErr)
# define piCerr
//! \relatesalso PIObject
//! \~english Macro used for conditional (piDebug && PIObject::debug()) output to PICout for subclasses of PIObject
//! \~russian Макрос для условного (piDebug && PIObject::debug()) вывода в PICout для наследников PIObject
//! \~english Macro used for conditional (piDebug && PIObject::debug()) output to PICout(StdOut) for subclasses of PIObject
//! \~russian Макрос для условного (piDebug && PIObject::debug()) вывода в PICout(StdOut) для наследников PIObject
# define piCoutObj
//! \relatesalso PIObject
//! \~english Macro used for conditional (piDebug && PIObject::debug()) output to PICout(StdErr) for subclasses of PIObject
//! \~russian Макрос для условного (piDebug && PIObject::debug()) вывода в PICout(StdErr) для наследников PIObject
# define piCerrObj
#else
# define piCout PICout(piDebug, PICoutStdStream::StdOut)
# define piCoutObj \
@@ -375,15 +384,19 @@ public:
static bool isOutputDeviceActive(OutputDevice d);
//! \~english Construct with external buffer.
//! \~russian Конструктор с внешним буфером.
static PICout withExternalBuffer(PIString * buffer,
PIFlags<PICoutManipulators::PICoutControl> controls = PICoutManipulators::AddSpaces);
//! \~english Construct with external buffer and ID "id". See \a Notifier for details
//! \~russian Конструктор с внешним буфером и ID "id". Подробнее \a Notifier
static PICout withExternalBuffer(PIString * buffer,
int id = 0,
PIFlags<PICoutManipulators::PICoutControl> controls = PICoutManipulators::AddSpaces |
PICoutManipulators::AddNewLine);
static PICout withExternalBufferAndID(PIString * buffer,
int id,
PIFlags<PICoutManipulators::PICoutControl> controls = PICoutManipulators::DefaultControls);
//! \~english Returns unique external buffer ID for later use in \a withExternalBuffer()
//! \~russian Возвращает уникальный ID для внешнего буфера для дальнейшего использования в \a withExternalBuffer()
//! \~english Returns unique external buffer ID for later use in \a withExternalBufferAndID()
//! \~russian Возвращает уникальный ID для внешнего буфера для дальнейшего использования в \a withExternalBufferAndID()
static int registerExternalBufferID();
static PIMutex & __mutex__();
@@ -397,7 +410,7 @@ private:
static OutputDevices devs;
PRIVATE_DECLARATION(PIP_EXPORT)
bool first_out_ = true, is_copy_ = false, format_changed_ = false, actve_ = true;
int int_base_ = 10, win_attr_ = 0, id_ = 0;
int int_base_ = 10, win_attr_ = 0, id_ = -1;
PIString * buffer_ = nullptr;
PICoutManipulators::PICoutControls ctrl_ = PICoutManipulators::DefaultControls;
PICoutStdStream stream_ = PICoutStdStream::StdOut;

View File

@@ -0,0 +1,160 @@
/*
BLAKE2 reference source code package - reference C implementations
Copyright 2012, Samuel Neves <sneves@dei.uc.pt>. You may use this under the
terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at
your option. The terms of these licenses can be found at:
- CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
- OpenSSL license : https://www.openssl.org/source/license.html
- Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
More information about the BLAKE2 hash function can be found at
https://blake2.net.
*/
#ifndef BLAKE2_IMPL_H
#define BLAKE2_IMPL_H
#include <stdint.h>
#include <string.h>
#if !defined(__cplusplus) && (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L)
#if defined(_MSC_VER)
#define BLAKE2_INLINE __inline
#elif defined(__GNUC__)
#define BLAKE2_INLINE __inline__
#else
#define BLAKE2_INLINE
#endif
#else
#define BLAKE2_INLINE inline
#endif
static BLAKE2_INLINE uint32_t load32( const void *src )
{
#if defined(NATIVE_LITTLE_ENDIAN)
uint32_t w;
memcpy(&w, src, sizeof w);
return w;
#else
const uint8_t *p = ( const uint8_t * )src;
return (( uint32_t )( p[0] ) << 0) |
(( uint32_t )( p[1] ) << 8) |
(( uint32_t )( p[2] ) << 16) |
(( uint32_t )( p[3] ) << 24) ;
#endif
}
static BLAKE2_INLINE uint64_t load64( const void *src )
{
#if defined(NATIVE_LITTLE_ENDIAN)
uint64_t w;
memcpy(&w, src, sizeof w);
return w;
#else
const uint8_t *p = ( const uint8_t * )src;
return (( uint64_t )( p[0] ) << 0) |
(( uint64_t )( p[1] ) << 8) |
(( uint64_t )( p[2] ) << 16) |
(( uint64_t )( p[3] ) << 24) |
(( uint64_t )( p[4] ) << 32) |
(( uint64_t )( p[5] ) << 40) |
(( uint64_t )( p[6] ) << 48) |
(( uint64_t )( p[7] ) << 56) ;
#endif
}
static BLAKE2_INLINE uint16_t load16( const void *src )
{
#if defined(NATIVE_LITTLE_ENDIAN)
uint16_t w;
memcpy(&w, src, sizeof w);
return w;
#else
const uint8_t *p = ( const uint8_t * )src;
return ( uint16_t )((( uint32_t )( p[0] ) << 0) |
(( uint32_t )( p[1] ) << 8));
#endif
}
static BLAKE2_INLINE void store16( void *dst, uint16_t w )
{
#if defined(NATIVE_LITTLE_ENDIAN)
memcpy(dst, &w, sizeof w);
#else
uint8_t *p = ( uint8_t * )dst;
*p++ = ( uint8_t )w; w >>= 8;
*p++ = ( uint8_t )w;
#endif
}
static BLAKE2_INLINE void store32( void *dst, uint32_t w )
{
#if defined(NATIVE_LITTLE_ENDIAN)
memcpy(dst, &w, sizeof w);
#else
uint8_t *p = ( uint8_t * )dst;
p[0] = (uint8_t)(w >> 0);
p[1] = (uint8_t)(w >> 8);
p[2] = (uint8_t)(w >> 16);
p[3] = (uint8_t)(w >> 24);
#endif
}
static BLAKE2_INLINE void store64( void *dst, uint64_t w )
{
#if defined(NATIVE_LITTLE_ENDIAN)
memcpy(dst, &w, sizeof w);
#else
uint8_t *p = ( uint8_t * )dst;
p[0] = (uint8_t)(w >> 0);
p[1] = (uint8_t)(w >> 8);
p[2] = (uint8_t)(w >> 16);
p[3] = (uint8_t)(w >> 24);
p[4] = (uint8_t)(w >> 32);
p[5] = (uint8_t)(w >> 40);
p[6] = (uint8_t)(w >> 48);
p[7] = (uint8_t)(w >> 56);
#endif
}
static BLAKE2_INLINE uint64_t load48( const void *src )
{
const uint8_t *p = ( const uint8_t * )src;
return (( uint64_t )( p[0] ) << 0) |
(( uint64_t )( p[1] ) << 8) |
(( uint64_t )( p[2] ) << 16) |
(( uint64_t )( p[3] ) << 24) |
(( uint64_t )( p[4] ) << 32) |
(( uint64_t )( p[5] ) << 40) ;
}
static BLAKE2_INLINE void store48( void *dst, uint64_t w )
{
uint8_t *p = ( uint8_t * )dst;
p[0] = (uint8_t)(w >> 0);
p[1] = (uint8_t)(w >> 8);
p[2] = (uint8_t)(w >> 16);
p[3] = (uint8_t)(w >> 24);
p[4] = (uint8_t)(w >> 32);
p[5] = (uint8_t)(w >> 40);
}
static BLAKE2_INLINE uint32_t rotr32( const uint32_t w, const unsigned c )
{
return ( w >> c ) | ( w << ( 32 - c ) );
}
static BLAKE2_INLINE uint64_t rotr64( const uint64_t w, const unsigned c )
{
return ( w >> c ) | ( w << ( 64 - c ) );
}
/* prevents compiler optimizing out memset() */
static BLAKE2_INLINE void secure_zero_memory(void *v, size_t n)
{
static void *(*const volatile memset_v)(void *, int, size_t) = &memset;
memset_v(v, 0, n);
}
#endif

View File

@@ -0,0 +1,195 @@
/*
BLAKE2 reference source code package - reference C implementations
Copyright 2012, Samuel Neves <sneves@dei.uc.pt>. You may use this under the
terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at
your option. The terms of these licenses can be found at:
- CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
- OpenSSL license : https://www.openssl.org/source/license.html
- Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
More information about the BLAKE2 hash function can be found at
https://blake2.net.
*/
#ifndef BLAKE2_H
#define BLAKE2_H
#include <stddef.h>
#include <stdint.h>
#if defined(_MSC_VER)
#define BLAKE2_PACKED(x) __pragma(pack(push, 1)) x __pragma(pack(pop))
#else
#define BLAKE2_PACKED(x) x __attribute__((packed))
#endif
#if defined(__cplusplus)
extern "C" {
#endif
enum blake2s_constant
{
BLAKE2S_BLOCKBYTES = 64,
BLAKE2S_OUTBYTES = 32,
BLAKE2S_KEYBYTES = 32,
BLAKE2S_SALTBYTES = 8,
BLAKE2S_PERSONALBYTES = 8
};
enum blake2b_constant
{
BLAKE2B_BLOCKBYTES = 128,
BLAKE2B_OUTBYTES = 64,
BLAKE2B_KEYBYTES = 64,
BLAKE2B_SALTBYTES = 16,
BLAKE2B_PERSONALBYTES = 16
};
typedef struct blake2s_state__
{
uint32_t h[8];
uint32_t t[2];
uint32_t f[2];
uint8_t buf[BLAKE2S_BLOCKBYTES];
size_t buflen;
size_t outlen;
uint8_t last_node;
} blake2s_state;
typedef struct blake2b_state__
{
uint64_t h[8];
uint64_t t[2];
uint64_t f[2];
uint8_t buf[BLAKE2B_BLOCKBYTES];
size_t buflen;
size_t outlen;
uint8_t last_node;
} blake2b_state;
typedef struct blake2sp_state__
{
blake2s_state S[8][1];
blake2s_state R[1];
uint8_t buf[8 * BLAKE2S_BLOCKBYTES];
size_t buflen;
size_t outlen;
} blake2sp_state;
typedef struct blake2bp_state__
{
blake2b_state S[4][1];
blake2b_state R[1];
uint8_t buf[4 * BLAKE2B_BLOCKBYTES];
size_t buflen;
size_t outlen;
} blake2bp_state;
BLAKE2_PACKED(struct blake2s_param__
{
uint8_t digest_length; /* 1 */
uint8_t key_length; /* 2 */
uint8_t fanout; /* 3 */
uint8_t depth; /* 4 */
uint32_t leaf_length; /* 8 */
uint32_t node_offset; /* 12 */
uint16_t xof_length; /* 14 */
uint8_t node_depth; /* 15 */
uint8_t inner_length; /* 16 */
/* uint8_t reserved[0]; */
uint8_t salt[BLAKE2S_SALTBYTES]; /* 24 */
uint8_t personal[BLAKE2S_PERSONALBYTES]; /* 32 */
});
typedef struct blake2s_param__ blake2s_param;
BLAKE2_PACKED(struct blake2b_param__
{
uint8_t digest_length; /* 1 */
uint8_t key_length; /* 2 */
uint8_t fanout; /* 3 */
uint8_t depth; /* 4 */
uint32_t leaf_length; /* 8 */
uint32_t node_offset; /* 12 */
uint32_t xof_length; /* 16 */
uint8_t node_depth; /* 17 */
uint8_t inner_length; /* 18 */
uint8_t reserved[14]; /* 32 */
uint8_t salt[BLAKE2B_SALTBYTES]; /* 48 */
uint8_t personal[BLAKE2B_PERSONALBYTES]; /* 64 */
});
typedef struct blake2b_param__ blake2b_param;
typedef struct blake2xs_state__
{
blake2s_state S[1];
blake2s_param P[1];
} blake2xs_state;
typedef struct blake2xb_state__
{
blake2b_state S[1];
blake2b_param P[1];
} blake2xb_state;
/* Padded structs result in a compile-time error */
enum {
BLAKE2_DUMMY_1 = 1/(int)(sizeof(blake2s_param) == BLAKE2S_OUTBYTES),
BLAKE2_DUMMY_2 = 1/(int)(sizeof(blake2b_param) == BLAKE2B_OUTBYTES)
};
/* Streaming API */
int blake2s_init( blake2s_state *S, size_t outlen );
int blake2s_init_key( blake2s_state *S, size_t outlen, const void *key, size_t keylen );
int blake2s_init_param( blake2s_state *S, const blake2s_param *P );
int blake2s_update( blake2s_state *S, const void *in, size_t inlen );
int blake2s_final( blake2s_state *S, void *out, size_t outlen );
int blake2b_init( blake2b_state *S, size_t outlen );
int blake2b_init_key( blake2b_state *S, size_t outlen, const void *key, size_t keylen );
int blake2b_init_param( blake2b_state *S, const blake2b_param *P );
int blake2b_update( blake2b_state *S, const void *in, size_t inlen );
int blake2b_final( blake2b_state *S, void *out, size_t outlen );
int blake2sp_init( blake2sp_state *S, size_t outlen );
int blake2sp_init_key( blake2sp_state *S, size_t outlen, const void *key, size_t keylen );
int blake2sp_update( blake2sp_state *S, const void *in, size_t inlen );
int blake2sp_final( blake2sp_state *S, void *out, size_t outlen );
int blake2bp_init( blake2bp_state *S, size_t outlen );
int blake2bp_init_key( blake2bp_state *S, size_t outlen, const void *key, size_t keylen );
int blake2bp_update( blake2bp_state *S, const void *in, size_t inlen );
int blake2bp_final( blake2bp_state *S, void *out, size_t outlen );
/* Variable output length API */
int blake2xs_init( blake2xs_state *S, const size_t outlen );
int blake2xs_init_key( blake2xs_state *S, const size_t outlen, const void *key, size_t keylen );
int blake2xs_update( blake2xs_state *S, const void *in, size_t inlen );
int blake2xs_final(blake2xs_state *S, void *out, size_t outlen);
int blake2xb_init( blake2xb_state *S, const size_t outlen );
int blake2xb_init_key( blake2xb_state *S, const size_t outlen, const void *key, size_t keylen );
int blake2xb_update( blake2xb_state *S, const void *in, size_t inlen );
int blake2xb_final(blake2xb_state *S, void *out, size_t outlen);
/* Simple API */
int blake2s( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
int blake2b( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
int blake2sp( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
int blake2bp( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
int blake2xs( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
int blake2xb( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
/* This is simply an alias for blake2b */
int blake2( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
#if defined(__cplusplus)
}
#endif
#endif

View File

@@ -0,0 +1,379 @@
/*
BLAKE2 reference source code package - reference C implementations
Copyright 2012, Samuel Neves <sneves@dei.uc.pt>. You may use this under the
terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at
your option. The terms of these licenses can be found at:
- CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
- OpenSSL license : https://www.openssl.org/source/license.html
- Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
More information about the BLAKE2 hash function can be found at
https://blake2.net.
*/
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "blake2.h"
#include "blake2-impl.h"
static const uint64_t blake2b_IV[8] =
{
0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL,
0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL,
0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL,
0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL
};
static const uint8_t blake2b_sigma[12][16] =
{
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } ,
{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } ,
{ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } ,
{ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } ,
{ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } ,
{ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } ,
{ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } ,
{ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } ,
{ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } ,
{ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } ,
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } ,
{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }
};
static void blake2b_set_lastnode( blake2b_state *S )
{
S->f[1] = (uint64_t)-1;
}
/* Some helper functions, not necessarily useful */
static int blake2b_is_lastblock( const blake2b_state *S )
{
return S->f[0] != 0;
}
static void blake2b_set_lastblock( blake2b_state *S )
{
if( S->last_node ) blake2b_set_lastnode( S );
S->f[0] = (uint64_t)-1;
}
static void blake2b_increment_counter( blake2b_state *S, const uint64_t inc )
{
S->t[0] += inc;
S->t[1] += ( S->t[0] < inc );
}
static void blake2b_init0( blake2b_state *S )
{
size_t i;
memset( S, 0, sizeof( blake2b_state ) );
for( i = 0; i < 8; ++i ) S->h[i] = blake2b_IV[i];
}
/* init xors IV with input parameter block */
int blake2b_init_param( blake2b_state *S, const blake2b_param *P )
{
const uint8_t *p = ( const uint8_t * )( P );
size_t i;
blake2b_init0( S );
/* IV XOR ParamBlock */
for( i = 0; i < 8; ++i )
S->h[i] ^= load64( p + sizeof( S->h[i] ) * i );
S->outlen = P->digest_length;
return 0;
}
int blake2b_init( blake2b_state *S, size_t outlen )
{
blake2b_param P[1];
if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1;
P->digest_length = (uint8_t)outlen;
P->key_length = 0;
P->fanout = 1;
P->depth = 1;
store32( &P->leaf_length, 0 );
store32( &P->node_offset, 0 );
store32( &P->xof_length, 0 );
P->node_depth = 0;
P->inner_length = 0;
memset( P->reserved, 0, sizeof( P->reserved ) );
memset( P->salt, 0, sizeof( P->salt ) );
memset( P->personal, 0, sizeof( P->personal ) );
return blake2b_init_param( S, P );
}
int blake2b_init_key( blake2b_state *S, size_t outlen, const void *key, size_t keylen )
{
blake2b_param P[1];
if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1;
if ( !key || !keylen || keylen > BLAKE2B_KEYBYTES ) return -1;
P->digest_length = (uint8_t)outlen;
P->key_length = (uint8_t)keylen;
P->fanout = 1;
P->depth = 1;
store32( &P->leaf_length, 0 );
store32( &P->node_offset, 0 );
store32( &P->xof_length, 0 );
P->node_depth = 0;
P->inner_length = 0;
memset( P->reserved, 0, sizeof( P->reserved ) );
memset( P->salt, 0, sizeof( P->salt ) );
memset( P->personal, 0, sizeof( P->personal ) );
if( blake2b_init_param( S, P ) < 0 ) return -1;
{
uint8_t block[BLAKE2B_BLOCKBYTES];
memset( block, 0, BLAKE2B_BLOCKBYTES );
memcpy( block, key, keylen );
blake2b_update( S, block, BLAKE2B_BLOCKBYTES );
secure_zero_memory( block, BLAKE2B_BLOCKBYTES ); /* Burn the key from stack */
}
return 0;
}
#define G(r,i,a,b,c,d) \
do { \
a = a + b + m[blake2b_sigma[r][2*i+0]]; \
d = rotr64(d ^ a, 32); \
c = c + d; \
b = rotr64(b ^ c, 24); \
a = a + b + m[blake2b_sigma[r][2*i+1]]; \
d = rotr64(d ^ a, 16); \
c = c + d; \
b = rotr64(b ^ c, 63); \
} while(0)
#define ROUND(r) \
do { \
G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \
G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \
G(r,2,v[ 2],v[ 6],v[10],v[14]); \
G(r,3,v[ 3],v[ 7],v[11],v[15]); \
G(r,4,v[ 0],v[ 5],v[10],v[15]); \
G(r,5,v[ 1],v[ 6],v[11],v[12]); \
G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \
G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \
} while(0)
static void blake2b_compress( blake2b_state *S, const uint8_t block[BLAKE2B_BLOCKBYTES] )
{
uint64_t m[16];
uint64_t v[16];
size_t i;
for( i = 0; i < 16; ++i ) {
m[i] = load64( block + i * sizeof( m[i] ) );
}
for( i = 0; i < 8; ++i ) {
v[i] = S->h[i];
}
v[ 8] = blake2b_IV[0];
v[ 9] = blake2b_IV[1];
v[10] = blake2b_IV[2];
v[11] = blake2b_IV[3];
v[12] = blake2b_IV[4] ^ S->t[0];
v[13] = blake2b_IV[5] ^ S->t[1];
v[14] = blake2b_IV[6] ^ S->f[0];
v[15] = blake2b_IV[7] ^ S->f[1];
ROUND( 0 );
ROUND( 1 );
ROUND( 2 );
ROUND( 3 );
ROUND( 4 );
ROUND( 5 );
ROUND( 6 );
ROUND( 7 );
ROUND( 8 );
ROUND( 9 );
ROUND( 10 );
ROUND( 11 );
for( i = 0; i < 8; ++i ) {
S->h[i] = S->h[i] ^ v[i] ^ v[i + 8];
}
}
#undef G
#undef ROUND
int blake2b_update( blake2b_state *S, const void *pin, size_t inlen )
{
const unsigned char * in = (const unsigned char *)pin;
if( inlen > 0 )
{
size_t left = S->buflen;
size_t fill = BLAKE2B_BLOCKBYTES - left;
if( inlen > fill )
{
S->buflen = 0;
memcpy( S->buf + left, in, fill ); /* Fill buffer */
blake2b_increment_counter( S, BLAKE2B_BLOCKBYTES );
blake2b_compress( S, S->buf ); /* Compress */
in += fill; inlen -= fill;
while(inlen > BLAKE2B_BLOCKBYTES) {
blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES);
blake2b_compress( S, in );
in += BLAKE2B_BLOCKBYTES;
inlen -= BLAKE2B_BLOCKBYTES;
}
}
memcpy( S->buf + S->buflen, in, inlen );
S->buflen += inlen;
}
return 0;
}
int blake2b_final( blake2b_state *S, void *out, size_t outlen )
{
uint8_t buffer[BLAKE2B_OUTBYTES] = {0};
size_t i;
if( out == NULL || outlen < S->outlen )
return -1;
if( blake2b_is_lastblock( S ) )
return -1;
blake2b_increment_counter( S, S->buflen );
blake2b_set_lastblock( S );
memset( S->buf + S->buflen, 0, BLAKE2B_BLOCKBYTES - S->buflen ); /* Padding */
blake2b_compress( S, S->buf );
for( i = 0; i < 8; ++i ) /* Output full hash to temp buffer */
store64( buffer + sizeof( S->h[i] ) * i, S->h[i] );
memcpy( out, buffer, S->outlen );
secure_zero_memory(buffer, sizeof(buffer));
return 0;
}
/* inlen, at least, should be uint64_t. Others can be size_t. */
int blake2b( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen )
{
blake2b_state S[1];
/* Verify parameters */
if ( NULL == in && inlen > 0 ) return -1;
if ( NULL == out ) return -1;
if( NULL == key && keylen > 0 ) return -1;
if( !outlen || outlen > BLAKE2B_OUTBYTES ) return -1;
if( keylen > BLAKE2B_KEYBYTES ) return -1;
if( keylen > 0 )
{
if( blake2b_init_key( S, outlen, key, keylen ) < 0 ) return -1;
}
else
{
if( blake2b_init( S, outlen ) < 0 ) return -1;
}
blake2b_update( S, ( const uint8_t * )in, inlen );
blake2b_final( S, out, outlen );
return 0;
}
int blake2( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ) {
return blake2b(out, outlen, in, inlen, key, keylen);
}
#if defined(SUPERCOP)
int crypto_hash( unsigned char *out, unsigned char *in, unsigned long long inlen )
{
return blake2b( out, BLAKE2B_OUTBYTES, in, inlen, NULL, 0 );
}
#endif
#if defined(BLAKE2B_SELFTEST)
#include <string.h>
#include "blake2-kat.h"
int main( void )
{
uint8_t key[BLAKE2B_KEYBYTES];
uint8_t buf[BLAKE2_KAT_LENGTH];
size_t i, step;
for( i = 0; i < BLAKE2B_KEYBYTES; ++i )
key[i] = ( uint8_t )i;
for( i = 0; i < BLAKE2_KAT_LENGTH; ++i )
buf[i] = ( uint8_t )i;
/* Test simple API */
for( i = 0; i < BLAKE2_KAT_LENGTH; ++i )
{
uint8_t hash[BLAKE2B_OUTBYTES];
blake2b( hash, BLAKE2B_OUTBYTES, buf, i, key, BLAKE2B_KEYBYTES );
if( 0 != memcmp( hash, blake2b_keyed_kat[i], BLAKE2B_OUTBYTES ) )
{
goto fail;
}
}
/* Test streaming API */
for(step = 1; step < BLAKE2B_BLOCKBYTES; ++step) {
for (i = 0; i < BLAKE2_KAT_LENGTH; ++i) {
uint8_t hash[BLAKE2B_OUTBYTES];
blake2b_state S;
uint8_t * p = buf;
size_t mlen = i;
int err = 0;
if( (err = blake2b_init_key(&S, BLAKE2B_OUTBYTES, key, BLAKE2B_KEYBYTES)) < 0 ) {
goto fail;
}
while (mlen >= step) {
if ( (err = blake2b_update(&S, p, step)) < 0 ) {
goto fail;
}
mlen -= step;
p += step;
}
if ( (err = blake2b_update(&S, p, mlen)) < 0) {
goto fail;
}
if ( (err = blake2b_final(&S, hash, BLAKE2B_OUTBYTES)) < 0) {
goto fail;
}
if (0 != memcmp(hash, blake2b_keyed_kat[i], BLAKE2B_OUTBYTES)) {
goto fail;
}
}
}
puts( "ok" );
return 0;
fail:
puts("error");
return -1;
}
#endif

View File

@@ -0,0 +1,359 @@
/*
BLAKE2 reference source code package - reference C implementations
Copyright 2012, Samuel Neves <sneves@dei.uc.pt>. You may use this under the
terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at
your option. The terms of these licenses can be found at:
- CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
- OpenSSL license : https://www.openssl.org/source/license.html
- Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
More information about the BLAKE2 hash function can be found at
https://blake2.net.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#if defined(_OPENMP)
#include <omp.h>
#endif
#include "blake2.h"
#include "blake2-impl.h"
#define PARALLELISM_DEGREE 4
/*
blake2b_init_param defaults to setting the expecting output length
from the digest_length parameter block field.
In some cases, however, we do not want this, as the output length
of these instances is given by inner_length instead.
*/
static int blake2bp_init_leaf_param( blake2b_state *S, const blake2b_param *P )
{
int err = blake2b_init_param(S, P);
S->outlen = P->inner_length;
return err;
}
static int blake2bp_init_leaf( blake2b_state *S, size_t outlen, size_t keylen, uint64_t offset )
{
blake2b_param P[1];
P->digest_length = (uint8_t)outlen;
P->key_length = (uint8_t)keylen;
P->fanout = PARALLELISM_DEGREE;
P->depth = 2;
store32( &P->leaf_length, 0 );
store32( &P->node_offset, offset );
store32( &P->xof_length, 0 );
P->node_depth = 0;
P->inner_length = BLAKE2B_OUTBYTES;
memset( P->reserved, 0, sizeof( P->reserved ) );
memset( P->salt, 0, sizeof( P->salt ) );
memset( P->personal, 0, sizeof( P->personal ) );
return blake2bp_init_leaf_param( S, P );
}
static int blake2bp_init_root( blake2b_state *S, size_t outlen, size_t keylen )
{
blake2b_param P[1];
P->digest_length = (uint8_t)outlen;
P->key_length = (uint8_t)keylen;
P->fanout = PARALLELISM_DEGREE;
P->depth = 2;
store32( &P->leaf_length, 0 );
store32( &P->node_offset, 0 );
store32( &P->xof_length, 0 );
P->node_depth = 1;
P->inner_length = BLAKE2B_OUTBYTES;
memset( P->reserved, 0, sizeof( P->reserved ) );
memset( P->salt, 0, sizeof( P->salt ) );
memset( P->personal, 0, sizeof( P->personal ) );
return blake2b_init_param( S, P );
}
int blake2bp_init( blake2bp_state *S, size_t outlen )
{
size_t i;
if( !outlen || outlen > BLAKE2B_OUTBYTES ) return -1;
memset( S->buf, 0, sizeof( S->buf ) );
S->buflen = 0;
S->outlen = outlen;
if( blake2bp_init_root( S->R, outlen, 0 ) < 0 )
return -1;
for( i = 0; i < PARALLELISM_DEGREE; ++i )
if( blake2bp_init_leaf( S->S[i], outlen, 0, i ) < 0 ) return -1;
S->R->last_node = 1;
S->S[PARALLELISM_DEGREE - 1]->last_node = 1;
return 0;
}
int blake2bp_init_key( blake2bp_state *S, size_t outlen, const void *key, size_t keylen )
{
size_t i;
if( !outlen || outlen > BLAKE2B_OUTBYTES ) return -1;
if( !key || !keylen || keylen > BLAKE2B_KEYBYTES ) return -1;
memset( S->buf, 0, sizeof( S->buf ) );
S->buflen = 0;
S->outlen = outlen;
if( blake2bp_init_root( S->R, outlen, keylen ) < 0 )
return -1;
for( i = 0; i < PARALLELISM_DEGREE; ++i )
if( blake2bp_init_leaf( S->S[i], outlen, keylen, i ) < 0 ) return -1;
S->R->last_node = 1;
S->S[PARALLELISM_DEGREE - 1]->last_node = 1;
{
uint8_t block[BLAKE2B_BLOCKBYTES];
memset( block, 0, BLAKE2B_BLOCKBYTES );
memcpy( block, key, keylen );
for( i = 0; i < PARALLELISM_DEGREE; ++i )
blake2b_update( S->S[i], block, BLAKE2B_BLOCKBYTES );
secure_zero_memory( block, BLAKE2B_BLOCKBYTES ); /* Burn the key from stack */
}
return 0;
}
int blake2bp_update( blake2bp_state *S, const void *pin, size_t inlen )
{
const unsigned char * in = (const unsigned char *)pin;
size_t left = S->buflen;
size_t fill = sizeof( S->buf ) - left;
size_t i;
if( left && inlen >= fill )
{
memcpy( S->buf + left, in, fill );
for( i = 0; i < PARALLELISM_DEGREE; ++i )
blake2b_update( S->S[i], S->buf + i * BLAKE2B_BLOCKBYTES, BLAKE2B_BLOCKBYTES );
in += fill;
inlen -= fill;
left = 0;
}
#if defined(_OPENMP)
#pragma omp parallel shared(S), num_threads(PARALLELISM_DEGREE)
#else
for( i = 0; i < PARALLELISM_DEGREE; ++i )
#endif
{
#if defined(_OPENMP)
size_t i = omp_get_thread_num();
#endif
size_t inlen__ = inlen;
const unsigned char *in__ = ( const unsigned char * )in;
in__ += i * BLAKE2B_BLOCKBYTES;
while( inlen__ >= PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES )
{
blake2b_update( S->S[i], in__, BLAKE2B_BLOCKBYTES );
in__ += PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES;
inlen__ -= PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES;
}
}
in += inlen - inlen % ( PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES );
inlen %= PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES;
if( inlen > 0 )
memcpy( S->buf + left, in, inlen );
S->buflen = left + inlen;
return 0;
}
int blake2bp_final( blake2bp_state *S, void *out, size_t outlen )
{
uint8_t hash[PARALLELISM_DEGREE][BLAKE2B_OUTBYTES];
size_t i;
if(out == NULL || outlen < S->outlen) {
return -1;
}
for( i = 0; i < PARALLELISM_DEGREE; ++i )
{
if( S->buflen > i * BLAKE2B_BLOCKBYTES )
{
size_t left = S->buflen - i * BLAKE2B_BLOCKBYTES;
if( left > BLAKE2B_BLOCKBYTES ) left = BLAKE2B_BLOCKBYTES;
blake2b_update( S->S[i], S->buf + i * BLAKE2B_BLOCKBYTES, left );
}
blake2b_final( S->S[i], hash[i], BLAKE2B_OUTBYTES );
}
for( i = 0; i < PARALLELISM_DEGREE; ++i )
blake2b_update( S->R, hash[i], BLAKE2B_OUTBYTES );
return blake2b_final( S->R, out, S->outlen );
}
int blake2bp( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen )
{
uint8_t hash[PARALLELISM_DEGREE][BLAKE2B_OUTBYTES];
blake2b_state S[PARALLELISM_DEGREE][1];
blake2b_state FS[1];
size_t i;
/* Verify parameters */
if ( NULL == in && inlen > 0 ) return -1;
if ( NULL == out ) return -1;
if( NULL == key && keylen > 0 ) return -1;
if( !outlen || outlen > BLAKE2B_OUTBYTES ) return -1;
if( keylen > BLAKE2B_KEYBYTES ) return -1;
for( i = 0; i < PARALLELISM_DEGREE; ++i )
if( blake2bp_init_leaf( S[i], outlen, keylen, i ) < 0 ) return -1;
S[PARALLELISM_DEGREE - 1]->last_node = 1; /* mark last node */
if( keylen > 0 )
{
uint8_t block[BLAKE2B_BLOCKBYTES];
memset( block, 0, BLAKE2B_BLOCKBYTES );
memcpy( block, key, keylen );
for( i = 0; i < PARALLELISM_DEGREE; ++i )
blake2b_update( S[i], block, BLAKE2B_BLOCKBYTES );
secure_zero_memory( block, BLAKE2B_BLOCKBYTES ); /* Burn the key from stack */
}
#if defined(_OPENMP)
#pragma omp parallel shared(S,hash), num_threads(PARALLELISM_DEGREE)
#else
for( i = 0; i < PARALLELISM_DEGREE; ++i )
#endif
{
#if defined(_OPENMP)
size_t i = omp_get_thread_num();
#endif
size_t inlen__ = inlen;
const unsigned char *in__ = ( const unsigned char * )in;
in__ += i * BLAKE2B_BLOCKBYTES;
while( inlen__ >= PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES )
{
blake2b_update( S[i], in__, BLAKE2B_BLOCKBYTES );
in__ += PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES;
inlen__ -= PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES;
}
if( inlen__ > i * BLAKE2B_BLOCKBYTES )
{
const size_t left = inlen__ - i * BLAKE2B_BLOCKBYTES;
const size_t len = left <= BLAKE2B_BLOCKBYTES ? left : BLAKE2B_BLOCKBYTES;
blake2b_update( S[i], in__, len );
}
blake2b_final( S[i], hash[i], BLAKE2B_OUTBYTES );
}
if( blake2bp_init_root( FS, outlen, keylen ) < 0 )
return -1;
FS->last_node = 1; /* Mark as last node */
for( i = 0; i < PARALLELISM_DEGREE; ++i )
blake2b_update( FS, hash[i], BLAKE2B_OUTBYTES );
return blake2b_final( FS, out, outlen );;
}
#if defined(BLAKE2BP_SELFTEST)
#include <string.h>
#include "blake2-kat.h"
int main( void )
{
uint8_t key[BLAKE2B_KEYBYTES];
uint8_t buf[BLAKE2_KAT_LENGTH];
size_t i, step;
for( i = 0; i < BLAKE2B_KEYBYTES; ++i )
key[i] = ( uint8_t )i;
for( i = 0; i < BLAKE2_KAT_LENGTH; ++i )
buf[i] = ( uint8_t )i;
/* Test simple API */
for( i = 0; i < BLAKE2_KAT_LENGTH; ++i )
{
uint8_t hash[BLAKE2B_OUTBYTES];
blake2bp( hash, BLAKE2B_OUTBYTES, buf, i, key, BLAKE2B_KEYBYTES );
if( 0 != memcmp( hash, blake2bp_keyed_kat[i], BLAKE2B_OUTBYTES ) )
{
goto fail;
}
}
/* Test streaming API */
for(step = 1; step < BLAKE2B_BLOCKBYTES; ++step) {
for (i = 0; i < BLAKE2_KAT_LENGTH; ++i) {
uint8_t hash[BLAKE2B_OUTBYTES];
blake2bp_state S;
uint8_t * p = buf;
size_t mlen = i;
int err = 0;
if( (err = blake2bp_init_key(&S, BLAKE2B_OUTBYTES, key, BLAKE2B_KEYBYTES)) < 0 ) {
goto fail;
}
while (mlen >= step) {
if ( (err = blake2bp_update(&S, p, step)) < 0 ) {
goto fail;
}
mlen -= step;
p += step;
}
if ( (err = blake2bp_update(&S, p, mlen)) < 0) {
goto fail;
}
if ( (err = blake2bp_final(&S, hash, BLAKE2B_OUTBYTES)) < 0) {
goto fail;
}
if (0 != memcmp(hash, blake2bp_keyed_kat[i], BLAKE2B_OUTBYTES)) {
goto fail;
}
}
}
puts( "ok" );
return 0;
fail:
puts("error");
return -1;
}
#endif

View File

@@ -0,0 +1,367 @@
/*
BLAKE2 reference source code package - reference C implementations
Copyright 2012, Samuel Neves <sneves@dei.uc.pt>. You may use this under the
terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at
your option. The terms of these licenses can be found at:
- CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
- OpenSSL license : https://www.openssl.org/source/license.html
- Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
More information about the BLAKE2 hash function can be found at
https://blake2.net.
*/
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "blake2.h"
#include "blake2-impl.h"
static const uint32_t blake2s_IV[8] =
{
0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, 0xA54FF53AUL,
0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL
};
static const uint8_t blake2s_sigma[10][16] =
{
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } ,
{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } ,
{ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } ,
{ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } ,
{ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } ,
{ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } ,
{ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } ,
{ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } ,
{ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } ,
{ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } ,
};
static void blake2s_set_lastnode( blake2s_state *S )
{
S->f[1] = (uint32_t)-1;
}
/* Some helper functions, not necessarily useful */
static int blake2s_is_lastblock( const blake2s_state *S )
{
return S->f[0] != 0;
}
static void blake2s_set_lastblock( blake2s_state *S )
{
if( S->last_node ) blake2s_set_lastnode( S );
S->f[0] = (uint32_t)-1;
}
static void blake2s_increment_counter( blake2s_state *S, const uint32_t inc )
{
S->t[0] += inc;
S->t[1] += ( S->t[0] < inc );
}
static void blake2s_init0( blake2s_state *S )
{
size_t i;
memset( S, 0, sizeof( blake2s_state ) );
for( i = 0; i < 8; ++i ) S->h[i] = blake2s_IV[i];
}
/* init2 xors IV with input parameter block */
int blake2s_init_param( blake2s_state *S, const blake2s_param *P )
{
const unsigned char *p = ( const unsigned char * )( P );
size_t i;
blake2s_init0( S );
/* IV XOR ParamBlock */
for( i = 0; i < 8; ++i )
S->h[i] ^= load32( &p[i * 4] );
S->outlen = P->digest_length;
return 0;
}
/* Sequential blake2s initialization */
int blake2s_init( blake2s_state *S, size_t outlen )
{
blake2s_param P[1];
/* Move interval verification here? */
if ( ( !outlen ) || ( outlen > BLAKE2S_OUTBYTES ) ) return -1;
P->digest_length = (uint8_t)outlen;
P->key_length = 0;
P->fanout = 1;
P->depth = 1;
store32( &P->leaf_length, 0 );
store32( &P->node_offset, 0 );
store16( &P->xof_length, 0 );
P->node_depth = 0;
P->inner_length = 0;
/* memset(P->reserved, 0, sizeof(P->reserved) ); */
memset( P->salt, 0, sizeof( P->salt ) );
memset( P->personal, 0, sizeof( P->personal ) );
return blake2s_init_param( S, P );
}
int blake2s_init_key( blake2s_state *S, size_t outlen, const void *key, size_t keylen )
{
blake2s_param P[1];
if ( ( !outlen ) || ( outlen > BLAKE2S_OUTBYTES ) ) return -1;
if ( !key || !keylen || keylen > BLAKE2S_KEYBYTES ) return -1;
P->digest_length = (uint8_t)outlen;
P->key_length = (uint8_t)keylen;
P->fanout = 1;
P->depth = 1;
store32( &P->leaf_length, 0 );
store32( &P->node_offset, 0 );
store16( &P->xof_length, 0 );
P->node_depth = 0;
P->inner_length = 0;
/* memset(P->reserved, 0, sizeof(P->reserved) ); */
memset( P->salt, 0, sizeof( P->salt ) );
memset( P->personal, 0, sizeof( P->personal ) );
if( blake2s_init_param( S, P ) < 0 ) return -1;
{
uint8_t block[BLAKE2S_BLOCKBYTES];
memset( block, 0, BLAKE2S_BLOCKBYTES );
memcpy( block, key, keylen );
blake2s_update( S, block, BLAKE2S_BLOCKBYTES );
secure_zero_memory( block, BLAKE2S_BLOCKBYTES ); /* Burn the key from stack */
}
return 0;
}
#define G(r,i,a,b,c,d) \
do { \
a = a + b + m[blake2s_sigma[r][2*i+0]]; \
d = rotr32(d ^ a, 16); \
c = c + d; \
b = rotr32(b ^ c, 12); \
a = a + b + m[blake2s_sigma[r][2*i+1]]; \
d = rotr32(d ^ a, 8); \
c = c + d; \
b = rotr32(b ^ c, 7); \
} while(0)
#define ROUND(r) \
do { \
G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \
G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \
G(r,2,v[ 2],v[ 6],v[10],v[14]); \
G(r,3,v[ 3],v[ 7],v[11],v[15]); \
G(r,4,v[ 0],v[ 5],v[10],v[15]); \
G(r,5,v[ 1],v[ 6],v[11],v[12]); \
G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \
G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \
} while(0)
static void blake2s_compress( blake2s_state *S, const uint8_t in[BLAKE2S_BLOCKBYTES] )
{
uint32_t m[16];
uint32_t v[16];
size_t i;
for( i = 0; i < 16; ++i ) {
m[i] = load32( in + i * sizeof( m[i] ) );
}
for( i = 0; i < 8; ++i ) {
v[i] = S->h[i];
}
v[ 8] = blake2s_IV[0];
v[ 9] = blake2s_IV[1];
v[10] = blake2s_IV[2];
v[11] = blake2s_IV[3];
v[12] = S->t[0] ^ blake2s_IV[4];
v[13] = S->t[1] ^ blake2s_IV[5];
v[14] = S->f[0] ^ blake2s_IV[6];
v[15] = S->f[1] ^ blake2s_IV[7];
ROUND( 0 );
ROUND( 1 );
ROUND( 2 );
ROUND( 3 );
ROUND( 4 );
ROUND( 5 );
ROUND( 6 );
ROUND( 7 );
ROUND( 8 );
ROUND( 9 );
for( i = 0; i < 8; ++i ) {
S->h[i] = S->h[i] ^ v[i] ^ v[i + 8];
}
}
#undef G
#undef ROUND
int blake2s_update( blake2s_state *S, const void *pin, size_t inlen )
{
const unsigned char * in = (const unsigned char *)pin;
if( inlen > 0 )
{
size_t left = S->buflen;
size_t fill = BLAKE2S_BLOCKBYTES - left;
if( inlen > fill )
{
S->buflen = 0;
memcpy( S->buf + left, in, fill ); /* Fill buffer */
blake2s_increment_counter( S, BLAKE2S_BLOCKBYTES );
blake2s_compress( S, S->buf ); /* Compress */
in += fill; inlen -= fill;
while(inlen > BLAKE2S_BLOCKBYTES) {
blake2s_increment_counter(S, BLAKE2S_BLOCKBYTES);
blake2s_compress( S, in );
in += BLAKE2S_BLOCKBYTES;
inlen -= BLAKE2S_BLOCKBYTES;
}
}
memcpy( S->buf + S->buflen, in, inlen );
S->buflen += inlen;
}
return 0;
}
int blake2s_final( blake2s_state *S, void *out, size_t outlen )
{
uint8_t buffer[BLAKE2S_OUTBYTES] = {0};
size_t i;
if( out == NULL || outlen < S->outlen )
return -1;
if( blake2s_is_lastblock( S ) )
return -1;
blake2s_increment_counter( S, ( uint32_t )S->buflen );
blake2s_set_lastblock( S );
memset( S->buf + S->buflen, 0, BLAKE2S_BLOCKBYTES - S->buflen ); /* Padding */
blake2s_compress( S, S->buf );
for( i = 0; i < 8; ++i ) /* Output full hash to temp buffer */
store32( buffer + sizeof( S->h[i] ) * i, S->h[i] );
memcpy( out, buffer, outlen );
secure_zero_memory(buffer, sizeof(buffer));
return 0;
}
int blake2s( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen )
{
blake2s_state S[1];
/* Verify parameters */
if ( NULL == in && inlen > 0 ) return -1;
if ( NULL == out ) return -1;
if ( NULL == key && keylen > 0) return -1;
if( !outlen || outlen > BLAKE2S_OUTBYTES ) return -1;
if( keylen > BLAKE2S_KEYBYTES ) return -1;
if( keylen > 0 )
{
if( blake2s_init_key( S, outlen, key, keylen ) < 0 ) return -1;
}
else
{
if( blake2s_init( S, outlen ) < 0 ) return -1;
}
blake2s_update( S, ( const uint8_t * )in, inlen );
blake2s_final( S, out, outlen );
return 0;
}
#if defined(SUPERCOP)
int crypto_hash( unsigned char *out, unsigned char *in, unsigned long long inlen )
{
return blake2s( out, BLAKE2S_OUTBYTES, in, inlen, NULL, 0 );
}
#endif
#if defined(BLAKE2S_SELFTEST)
#include <string.h>
#include "blake2-kat.h"
int main( void )
{
uint8_t key[BLAKE2S_KEYBYTES];
uint8_t buf[BLAKE2_KAT_LENGTH];
size_t i, step;
for( i = 0; i < BLAKE2S_KEYBYTES; ++i )
key[i] = ( uint8_t )i;
for( i = 0; i < BLAKE2_KAT_LENGTH; ++i )
buf[i] = ( uint8_t )i;
/* Test simple API */
for( i = 0; i < BLAKE2_KAT_LENGTH; ++i )
{
uint8_t hash[BLAKE2S_OUTBYTES];
blake2s( hash, BLAKE2S_OUTBYTES, buf, i, key, BLAKE2S_KEYBYTES );
if( 0 != memcmp( hash, blake2s_keyed_kat[i], BLAKE2S_OUTBYTES ) )
{
goto fail;
}
}
/* Test streaming API */
for(step = 1; step < BLAKE2S_BLOCKBYTES; ++step) {
for (i = 0; i < BLAKE2_KAT_LENGTH; ++i) {
uint8_t hash[BLAKE2S_OUTBYTES];
blake2s_state S;
uint8_t * p = buf;
size_t mlen = i;
int err = 0;
if( (err = blake2s_init_key(&S, BLAKE2S_OUTBYTES, key, BLAKE2S_KEYBYTES)) < 0 ) {
goto fail;
}
while (mlen >= step) {
if ( (err = blake2s_update(&S, p, step)) < 0 ) {
goto fail;
}
mlen -= step;
p += step;
}
if ( (err = blake2s_update(&S, p, mlen)) < 0) {
goto fail;
}
if ( (err = blake2s_final(&S, hash, BLAKE2S_OUTBYTES)) < 0) {
goto fail;
}
if (0 != memcmp(hash, blake2s_keyed_kat[i], BLAKE2S_OUTBYTES)) {
goto fail;
}
}
}
puts( "ok" );
return 0;
fail:
puts("error");
return -1;
}
#endif

View File

@@ -0,0 +1,359 @@
/*
BLAKE2 reference source code package - reference C implementations
Copyright 2012, Samuel Neves <sneves@dei.uc.pt>. You may use this under the
terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at
your option. The terms of these licenses can be found at:
- CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
- OpenSSL license : https://www.openssl.org/source/license.html
- Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
More information about the BLAKE2 hash function can be found at
https://blake2.net.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#if defined(_OPENMP)
#include <omp.h>
#endif
#include "blake2.h"
#include "blake2-impl.h"
#define PARALLELISM_DEGREE 8
/*
blake2sp_init_param defaults to setting the expecting output length
from the digest_length parameter block field.
In some cases, however, we do not want this, as the output length
of these instances is given by inner_length instead.
*/
static int blake2sp_init_leaf_param( blake2s_state *S, const blake2s_param *P )
{
int err = blake2s_init_param(S, P);
S->outlen = P->inner_length;
return err;
}
static int blake2sp_init_leaf( blake2s_state *S, size_t outlen, size_t keylen, uint64_t offset )
{
blake2s_param P[1];
P->digest_length = (uint8_t)outlen;
P->key_length = (uint8_t)keylen;
P->fanout = PARALLELISM_DEGREE;
P->depth = 2;
store32( &P->leaf_length, 0 );
store32( &P->node_offset, offset );
store16( &P->xof_length, 0 );
P->node_depth = 0;
P->inner_length = BLAKE2S_OUTBYTES;
memset( P->salt, 0, sizeof( P->salt ) );
memset( P->personal, 0, sizeof( P->personal ) );
return blake2sp_init_leaf_param( S, P );
}
static int blake2sp_init_root( blake2s_state *S, size_t outlen, size_t keylen )
{
blake2s_param P[1];
P->digest_length = (uint8_t)outlen;
P->key_length = (uint8_t)keylen;
P->fanout = PARALLELISM_DEGREE;
P->depth = 2;
store32( &P->leaf_length, 0 );
store32( &P->node_offset, 0 );
store16( &P->xof_length, 0 );
P->node_depth = 1;
P->inner_length = BLAKE2S_OUTBYTES;
memset( P->salt, 0, sizeof( P->salt ) );
memset( P->personal, 0, sizeof( P->personal ) );
return blake2s_init_param( S, P );
}
int blake2sp_init( blake2sp_state *S, size_t outlen )
{
size_t i;
if( !outlen || outlen > BLAKE2S_OUTBYTES ) return -1;
memset( S->buf, 0, sizeof( S->buf ) );
S->buflen = 0;
S->outlen = outlen;
if( blake2sp_init_root( S->R, outlen, 0 ) < 0 )
return -1;
for( i = 0; i < PARALLELISM_DEGREE; ++i )
if( blake2sp_init_leaf( S->S[i], outlen, 0, i ) < 0 ) return -1;
S->R->last_node = 1;
S->S[PARALLELISM_DEGREE - 1]->last_node = 1;
return 0;
}
int blake2sp_init_key( blake2sp_state *S, size_t outlen, const void *key, size_t keylen )
{
size_t i;
if( !outlen || outlen > BLAKE2S_OUTBYTES ) return -1;
if( !key || !keylen || keylen > BLAKE2S_KEYBYTES ) return -1;
memset( S->buf, 0, sizeof( S->buf ) );
S->buflen = 0;
S->outlen = outlen;
if( blake2sp_init_root( S->R, outlen, keylen ) < 0 )
return -1;
for( i = 0; i < PARALLELISM_DEGREE; ++i )
if( blake2sp_init_leaf( S->S[i], outlen, keylen, i ) < 0 ) return -1;
S->R->last_node = 1;
S->S[PARALLELISM_DEGREE - 1]->last_node = 1;
{
uint8_t block[BLAKE2S_BLOCKBYTES];
memset( block, 0, BLAKE2S_BLOCKBYTES );
memcpy( block, key, keylen );
for( i = 0; i < PARALLELISM_DEGREE; ++i )
blake2s_update( S->S[i], block, BLAKE2S_BLOCKBYTES );
secure_zero_memory( block, BLAKE2S_BLOCKBYTES ); /* Burn the key from stack */
}
return 0;
}
int blake2sp_update( blake2sp_state *S, const void *pin, size_t inlen )
{
const unsigned char * in = (const unsigned char *)pin;
size_t left = S->buflen;
size_t fill = sizeof( S->buf ) - left;
size_t i;
if( left && inlen >= fill )
{
memcpy( S->buf + left, in, fill );
for( i = 0; i < PARALLELISM_DEGREE; ++i )
blake2s_update( S->S[i], S->buf + i * BLAKE2S_BLOCKBYTES, BLAKE2S_BLOCKBYTES );
in += fill;
inlen -= fill;
left = 0;
}
#if defined(_OPENMP)
#pragma omp parallel shared(S), num_threads(PARALLELISM_DEGREE)
#else
for( i = 0; i < PARALLELISM_DEGREE; ++i )
#endif
{
#if defined(_OPENMP)
size_t i = omp_get_thread_num();
#endif
size_t inlen__ = inlen;
const unsigned char *in__ = ( const unsigned char * )in;
in__ += i * BLAKE2S_BLOCKBYTES;
while( inlen__ >= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES )
{
blake2s_update( S->S[i], in__, BLAKE2S_BLOCKBYTES );
in__ += PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
inlen__ -= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
}
}
in += inlen - inlen % ( PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES );
inlen %= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
if( inlen > 0 )
memcpy( S->buf + left, in, inlen );
S->buflen = left + inlen;
return 0;
}
int blake2sp_final( blake2sp_state *S, void *out, size_t outlen )
{
uint8_t hash[PARALLELISM_DEGREE][BLAKE2S_OUTBYTES];
size_t i;
if(out == NULL || outlen < S->outlen) {
return -1;
}
for( i = 0; i < PARALLELISM_DEGREE; ++i )
{
if( S->buflen > i * BLAKE2S_BLOCKBYTES )
{
size_t left = S->buflen - i * BLAKE2S_BLOCKBYTES;
if( left > BLAKE2S_BLOCKBYTES ) left = BLAKE2S_BLOCKBYTES;
blake2s_update( S->S[i], S->buf + i * BLAKE2S_BLOCKBYTES, left );
}
blake2s_final( S->S[i], hash[i], BLAKE2S_OUTBYTES );
}
for( i = 0; i < PARALLELISM_DEGREE; ++i )
blake2s_update( S->R, hash[i], BLAKE2S_OUTBYTES );
return blake2s_final( S->R, out, S->outlen );
}
int blake2sp( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen )
{
uint8_t hash[PARALLELISM_DEGREE][BLAKE2S_OUTBYTES];
blake2s_state S[PARALLELISM_DEGREE][1];
blake2s_state FS[1];
size_t i;
/* Verify parameters */
if ( NULL == in && inlen > 0 ) return -1;
if ( NULL == out ) return -1;
if ( NULL == key && keylen > 0) return -1;
if( !outlen || outlen > BLAKE2S_OUTBYTES ) return -1;
if( keylen > BLAKE2S_KEYBYTES ) return -1;
for( i = 0; i < PARALLELISM_DEGREE; ++i )
if( blake2sp_init_leaf( S[i], outlen, keylen, i ) < 0 ) return -1;
S[PARALLELISM_DEGREE - 1]->last_node = 1; /* mark last node */
if( keylen > 0 )
{
uint8_t block[BLAKE2S_BLOCKBYTES];
memset( block, 0, BLAKE2S_BLOCKBYTES );
memcpy( block, key, keylen );
for( i = 0; i < PARALLELISM_DEGREE; ++i )
blake2s_update( S[i], block, BLAKE2S_BLOCKBYTES );
secure_zero_memory( block, BLAKE2S_BLOCKBYTES ); /* Burn the key from stack */
}
#if defined(_OPENMP)
#pragma omp parallel shared(S,hash), num_threads(PARALLELISM_DEGREE)
#else
for( i = 0; i < PARALLELISM_DEGREE; ++i )
#endif
{
#if defined(_OPENMP)
size_t i = omp_get_thread_num();
#endif
size_t inlen__ = inlen;
const unsigned char *in__ = ( const unsigned char * )in;
in__ += i * BLAKE2S_BLOCKBYTES;
while( inlen__ >= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES )
{
blake2s_update( S[i], in__, BLAKE2S_BLOCKBYTES );
in__ += PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
inlen__ -= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
}
if( inlen__ > i * BLAKE2S_BLOCKBYTES )
{
const size_t left = inlen__ - i * BLAKE2S_BLOCKBYTES;
const size_t len = left <= BLAKE2S_BLOCKBYTES ? left : BLAKE2S_BLOCKBYTES;
blake2s_update( S[i], in__, len );
}
blake2s_final( S[i], hash[i], BLAKE2S_OUTBYTES );
}
if( blake2sp_init_root( FS, outlen, keylen ) < 0 )
return -1;
FS->last_node = 1;
for( i = 0; i < PARALLELISM_DEGREE; ++i )
blake2s_update( FS, hash[i], BLAKE2S_OUTBYTES );
return blake2s_final( FS, out, outlen );
}
#if defined(BLAKE2SP_SELFTEST)
#include <string.h>
#include "blake2-kat.h"
int main( void )
{
uint8_t key[BLAKE2S_KEYBYTES];
uint8_t buf[BLAKE2_KAT_LENGTH];
size_t i, step;
for( i = 0; i < BLAKE2S_KEYBYTES; ++i )
key[i] = ( uint8_t )i;
for( i = 0; i < BLAKE2_KAT_LENGTH; ++i )
buf[i] = ( uint8_t )i;
/* Test simple API */
for( i = 0; i < BLAKE2_KAT_LENGTH; ++i )
{
uint8_t hash[BLAKE2S_OUTBYTES];
blake2sp( hash, BLAKE2S_OUTBYTES, buf, i, key, BLAKE2S_KEYBYTES );
if( 0 != memcmp( hash, blake2sp_keyed_kat[i], BLAKE2S_OUTBYTES ) )
{
goto fail;
}
}
/* Test streaming API */
for(step = 1; step < BLAKE2S_BLOCKBYTES; ++step) {
for (i = 0; i < BLAKE2_KAT_LENGTH; ++i) {
uint8_t hash[BLAKE2S_OUTBYTES];
blake2sp_state S;
uint8_t * p = buf;
size_t mlen = i;
int err = 0;
if( (err = blake2sp_init_key(&S, BLAKE2S_OUTBYTES, key, BLAKE2S_KEYBYTES)) < 0 ) {
goto fail;
}
while (mlen >= step) {
if ( (err = blake2sp_update(&S, p, step)) < 0 ) {
goto fail;
}
mlen -= step;
p += step;
}
if ( (err = blake2sp_update(&S, p, mlen)) < 0) {
goto fail;
}
if ( (err = blake2sp_final(&S, hash, BLAKE2S_OUTBYTES)) < 0) {
goto fail;
}
if (0 != memcmp(hash, blake2sp_keyed_kat[i], BLAKE2S_OUTBYTES)) {
goto fail;
}
}
}
puts( "ok" );
return 0;
fail:
puts("error");
return -1;
}
#endif

View File

@@ -0,0 +1,241 @@
/*
BLAKE2 reference source code package - reference C implementations
Copyright 2016, JP Aumasson <jeanphilippe.aumasson@gmail.com>.
Copyright 2016, Samuel Neves <sneves@dei.uc.pt>.
You may use this under the terms of the CC0, the OpenSSL Licence, or
the Apache Public License 2.0, at your option. The terms of these
licenses can be found at:
- CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
- OpenSSL license : https://www.openssl.org/source/license.html
- Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
More information about the BLAKE2 hash function can be found at
https://blake2.net.
*/
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "blake2.h"
#include "blake2-impl.h"
int blake2xb_init( blake2xb_state *S, const size_t outlen ) {
return blake2xb_init_key(S, outlen, NULL, 0);
}
int blake2xb_init_key( blake2xb_state *S, const size_t outlen, const void *key, size_t keylen)
{
if ( outlen == 0 || outlen > 0xFFFFFFFFUL ) {
return -1;
}
if (NULL != key && keylen > BLAKE2B_KEYBYTES) {
return -1;
}
if (NULL == key && keylen > 0) {
return -1;
}
/* Initialize parameter block */
S->P->digest_length = BLAKE2B_OUTBYTES;
S->P->key_length = keylen;
S->P->fanout = 1;
S->P->depth = 1;
store32( &S->P->leaf_length, 0 );
store32( &S->P->node_offset, 0 );
store32( &S->P->xof_length, outlen );
S->P->node_depth = 0;
S->P->inner_length = 0;
memset( S->P->reserved, 0, sizeof( S->P->reserved ) );
memset( S->P->salt, 0, sizeof( S->P->salt ) );
memset( S->P->personal, 0, sizeof( S->P->personal ) );
if( blake2b_init_param( S->S, S->P ) < 0 ) {
return -1;
}
if (keylen > 0) {
uint8_t block[BLAKE2B_BLOCKBYTES];
memset(block, 0, BLAKE2B_BLOCKBYTES);
memcpy(block, key, keylen);
blake2b_update(S->S, block, BLAKE2B_BLOCKBYTES);
secure_zero_memory(block, BLAKE2B_BLOCKBYTES);
}
return 0;
}
int blake2xb_update( blake2xb_state *S, const void *in, size_t inlen ) {
return blake2b_update( S->S, in, inlen );
}
int blake2xb_final( blake2xb_state *S, void *out, size_t outlen) {
blake2b_state C[1];
blake2b_param P[1];
uint32_t xof_length = load32(&S->P->xof_length);
uint8_t root[BLAKE2B_BLOCKBYTES];
size_t i;
if (NULL == out) {
return -1;
}
/* outlen must match the output size defined in xof_length, */
/* unless it was -1, in which case anything goes except 0. */
if(xof_length == 0xFFFFFFFFUL) {
if(outlen == 0) {
return -1;
}
} else {
if(outlen != xof_length) {
return -1;
}
}
/* Finalize the root hash */
if (blake2b_final(S->S, root, BLAKE2B_OUTBYTES) < 0) {
return -1;
}
/* Set common block structure values */
/* Copy values from parent instance, and only change the ones below */
memcpy(P, S->P, sizeof(blake2b_param));
P->key_length = 0;
P->fanout = 0;
P->depth = 0;
store32(&P->leaf_length, BLAKE2B_OUTBYTES);
P->inner_length = BLAKE2B_OUTBYTES;
P->node_depth = 0;
for (i = 0; outlen > 0; ++i) {
const size_t block_size = (outlen < BLAKE2B_OUTBYTES) ? outlen : BLAKE2B_OUTBYTES;
/* Initialize state */
P->digest_length = block_size;
store32(&P->node_offset, i);
blake2b_init_param(C, P);
/* Process key if needed */
blake2b_update(C, root, BLAKE2B_OUTBYTES);
if (blake2b_final(C, (uint8_t *)out + i * BLAKE2B_OUTBYTES, block_size) < 0 ) {
return -1;
}
outlen -= block_size;
}
secure_zero_memory(root, sizeof(root));
secure_zero_memory(P, sizeof(P));
secure_zero_memory(C, sizeof(C));
/* Put blake2xb in an invalid state? cf. blake2s_is_lastblock */
return 0;
}
int blake2xb(void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen)
{
blake2xb_state S[1];
/* Verify parameters */
if (NULL == in && inlen > 0)
return -1;
if (NULL == out)
return -1;
if (NULL == key && keylen > 0)
return -1;
if (keylen > BLAKE2B_KEYBYTES)
return -1;
if (outlen == 0)
return -1;
/* Initialize the root block structure */
if (blake2xb_init_key(S, outlen, key, keylen) < 0) {
return -1;
}
/* Absorb the input message */
blake2xb_update(S, in, inlen);
/* Compute the root node of the tree and the final hash using the counter construction */
return blake2xb_final(S, out, outlen);
}
#if defined(BLAKE2XB_SELFTEST)
#include <string.h>
#include "blake2-kat.h"
int main( void )
{
uint8_t key[BLAKE2B_KEYBYTES];
uint8_t buf[BLAKE2_KAT_LENGTH];
size_t i, step, outlen;
for( i = 0; i < BLAKE2B_KEYBYTES; ++i ) {
key[i] = ( uint8_t )i;
}
for( i = 0; i < BLAKE2_KAT_LENGTH; ++i ) {
buf[i] = ( uint8_t )i;
}
/* Testing length of outputs rather than inputs */
/* (Test of input lengths mostly covered by blake2b tests) */
/* Test simple API */
for( outlen = 1; outlen <= BLAKE2_KAT_LENGTH; ++outlen )
{
uint8_t hash[BLAKE2_KAT_LENGTH] = {0};
if( blake2xb( hash, outlen, buf, BLAKE2_KAT_LENGTH, key, BLAKE2B_KEYBYTES ) < 0 ) {
goto fail;
}
if( 0 != memcmp( hash, blake2xb_keyed_kat[outlen-1], outlen ) )
{
goto fail;
}
}
/* Test streaming API */
for(step = 1; step < BLAKE2B_BLOCKBYTES; ++step) {
for (outlen = 1; outlen <= BLAKE2_KAT_LENGTH; ++outlen) {
uint8_t hash[BLAKE2_KAT_LENGTH];
blake2xb_state S;
uint8_t * p = buf;
size_t mlen = BLAKE2_KAT_LENGTH;
int err = 0;
if( (err = blake2xb_init_key(&S, outlen, key, BLAKE2B_KEYBYTES)) < 0 ) {
goto fail;
}
while (mlen >= step) {
if ( (err = blake2xb_update(&S, p, step)) < 0 ) {
goto fail;
}
mlen -= step;
p += step;
}
if ( (err = blake2xb_update(&S, p, mlen)) < 0) {
goto fail;
}
if ( (err = blake2xb_final(&S, hash, outlen)) < 0) {
goto fail;
}
if (0 != memcmp(hash, blake2xb_keyed_kat[outlen-1], outlen)) {
goto fail;
}
}
}
puts( "ok" );
return 0;
fail:
puts("error");
return -1;
}
#endif

View File

@@ -0,0 +1,239 @@
/*
BLAKE2 reference source code package - reference C implementations
Copyright 2016, JP Aumasson <jeanphilippe.aumasson@gmail.com>.
Copyright 2016, Samuel Neves <sneves@dei.uc.pt>.
You may use this under the terms of the CC0, the OpenSSL Licence, or
the Apache Public License 2.0, at your option. The terms of these
licenses can be found at:
- CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
- OpenSSL license : https://www.openssl.org/source/license.html
- Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
More information about the BLAKE2 hash function can be found at
https://blake2.net.
*/
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "blake2.h"
#include "blake2-impl.h"
int blake2xs_init( blake2xs_state *S, const size_t outlen ) {
return blake2xs_init_key(S, outlen, NULL, 0);
}
int blake2xs_init_key( blake2xs_state *S, const size_t outlen, const void *key, size_t keylen )
{
if ( outlen == 0 || outlen > 0xFFFFUL ) {
return -1;
}
if (NULL != key && keylen > BLAKE2S_KEYBYTES) {
return -1;
}
if (NULL == key && keylen > 0) {
return -1;
}
/* Initialize parameter block */
S->P->digest_length = BLAKE2S_OUTBYTES;
S->P->key_length = keylen;
S->P->fanout = 1;
S->P->depth = 1;
store32( &S->P->leaf_length, 0 );
store32( &S->P->node_offset, 0 );
store16( &S->P->xof_length, outlen );
S->P->node_depth = 0;
S->P->inner_length = 0;
memset( S->P->salt, 0, sizeof( S->P->salt ) );
memset( S->P->personal, 0, sizeof( S->P->personal ) );
if( blake2s_init_param( S->S, S->P ) < 0 ) {
return -1;
}
if (keylen > 0) {
uint8_t block[BLAKE2S_BLOCKBYTES];
memset(block, 0, BLAKE2S_BLOCKBYTES);
memcpy(block, key, keylen);
blake2s_update(S->S, block, BLAKE2S_BLOCKBYTES);
secure_zero_memory(block, BLAKE2S_BLOCKBYTES);
}
return 0;
}
int blake2xs_update( blake2xs_state *S, const void *in, size_t inlen ) {
return blake2s_update( S->S, in, inlen );
}
int blake2xs_final(blake2xs_state *S, void *out, size_t outlen) {
blake2s_state C[1];
blake2s_param P[1];
uint16_t xof_length = load16(&S->P->xof_length);
uint8_t root[BLAKE2S_BLOCKBYTES];
size_t i;
if (NULL == out) {
return -1;
}
/* outlen must match the output size defined in xof_length, */
/* unless it was -1, in which case anything goes except 0. */
if(xof_length == 0xFFFFUL) {
if(outlen == 0) {
return -1;
}
} else {
if(outlen != xof_length) {
return -1;
}
}
/* Finalize the root hash */
if (blake2s_final(S->S, root, BLAKE2S_OUTBYTES) < 0) {
return -1;
}
/* Set common block structure values */
/* Copy values from parent instance, and only change the ones below */
memcpy(P, S->P, sizeof(blake2s_param));
P->key_length = 0;
P->fanout = 0;
P->depth = 0;
store32(&P->leaf_length, BLAKE2S_OUTBYTES);
P->inner_length = BLAKE2S_OUTBYTES;
P->node_depth = 0;
for (i = 0; outlen > 0; ++i) {
const size_t block_size = (outlen < BLAKE2S_OUTBYTES) ? outlen : BLAKE2S_OUTBYTES;
/* Initialize state */
P->digest_length = block_size;
store32(&P->node_offset, i);
blake2s_init_param(C, P);
/* Process key if needed */
blake2s_update(C, root, BLAKE2S_OUTBYTES);
if (blake2s_final(C, (uint8_t *)out + i * BLAKE2S_OUTBYTES, block_size) < 0) {
return -1;
}
outlen -= block_size;
}
secure_zero_memory(root, sizeof(root));
secure_zero_memory(P, sizeof(P));
secure_zero_memory(C, sizeof(C));
/* Put blake2xs in an invalid state? cf. blake2s_is_lastblock */
return 0;
}
int blake2xs(void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen)
{
blake2xs_state S[1];
/* Verify parameters */
if (NULL == in && inlen > 0)
return -1;
if (NULL == out)
return -1;
if (NULL == key && keylen > 0)
return -1;
if (keylen > BLAKE2S_KEYBYTES)
return -1;
if (outlen == 0)
return -1;
/* Initialize the root block structure */
if (blake2xs_init_key(S, outlen, key, keylen) < 0) {
return -1;
}
/* Absorb the input message */
blake2xs_update(S, in, inlen);
/* Compute the root node of the tree and the final hash using the counter construction */
return blake2xs_final(S, out, outlen);
}
#if defined(BLAKE2XS_SELFTEST)
#include <string.h>
#include "blake2-kat.h"
int main( void )
{
uint8_t key[BLAKE2S_KEYBYTES];
uint8_t buf[BLAKE2_KAT_LENGTH];
size_t i, step, outlen;
for( i = 0; i < BLAKE2S_KEYBYTES; ++i ) {
key[i] = ( uint8_t )i;
}
for( i = 0; i < BLAKE2_KAT_LENGTH; ++i ) {
buf[i] = ( uint8_t )i;
}
/* Testing length of outputs rather than inputs */
/* (Test of input lengths mostly covered by blake2s tests) */
/* Test simple API */
for( outlen = 1; outlen <= BLAKE2_KAT_LENGTH; ++outlen )
{
uint8_t hash[BLAKE2_KAT_LENGTH] = {0};
if( blake2xs( hash, outlen, buf, BLAKE2_KAT_LENGTH, key, BLAKE2S_KEYBYTES ) < 0 ) {
goto fail;
}
if( 0 != memcmp( hash, blake2xs_keyed_kat[outlen-1], outlen ) )
{
goto fail;
}
}
/* Test streaming API */
for(step = 1; step < BLAKE2S_BLOCKBYTES; ++step) {
for (outlen = 1; outlen <= BLAKE2_KAT_LENGTH; ++outlen) {
uint8_t hash[BLAKE2_KAT_LENGTH];
blake2xs_state S;
uint8_t * p = buf;
size_t mlen = BLAKE2_KAT_LENGTH;
int err = 0;
if( (err = blake2xs_init_key(&S, outlen, key, BLAKE2S_KEYBYTES)) < 0 ) {
goto fail;
}
while (mlen >= step) {
if ( (err = blake2xs_update(&S, p, step)) < 0 ) {
goto fail;
}
mlen -= step;
p += step;
}
if ( (err = blake2xs_update(&S, p, mlen)) < 0) {
goto fail;
}
if ( (err = blake2xs_final(&S, hash, outlen)) < 0) {
goto fail;
}
if (0 != memcmp(hash, blake2xs_keyed_kat[outlen-1], outlen)) {
goto fail;
}
}
}
puts( "ok" );
return 0;
fail:
puts("error");
return -1;
}
#endif

View File

@@ -0,0 +1,153 @@
/*
PIP - Platform Independent Primitives
Digest algorithms
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pidigest.h"
#include "pidigest_blake2_p.h"
#include "pidigest_md2_p.h"
#include "pidigest_md4_p.h"
#include "pidigest_md5_p.h"
#include "pidigest_sha1_p.h"
#include "pidigest_sha2_p.h"
int PIDigest::hashLength(Type type) {
switch (type) {
case Type::MD2: return 16;
case Type::MD4: return 16;
case Type::MD5: return 16;
case Type::SHA1: return 20;
case Type::SHA2_224: return 28;
case Type::SHA2_256: return 32;
case Type::SHA2_384: return 48;
case Type::SHA2_512: return 64;
case Type::SHA2_512_224: return 28;
case Type::SHA2_512_256: return 32;
case Type::BLAKE2s_128: return 16;
case Type::BLAKE2s_160: return 20;
case Type::BLAKE2s_224: return 28;
case Type::BLAKE2s_256: return 32;
case Type::BLAKE2b_128: return 16;
case Type::BLAKE2b_160: return 20;
case Type::BLAKE2b_224: return 28;
case Type::BLAKE2b_256: return 32;
case Type::BLAKE2b_384: return 48;
case Type::BLAKE2b_512: return 64;
default: break;
}
return 0;
}
int PIDigest::blockLength(Type type) {
switch (type) {
case Type::MD2: return 16;
case Type::MD4:
case Type::MD5: return 64;
case Type::SHA1: return 64;
case Type::SHA2_224:
case Type::SHA2_256: return 64;
case Type::SHA2_384:
case Type::SHA2_512:
case Type::SHA2_512_224:
case Type::SHA2_512_256: return 128;
case Type::BLAKE2s_128:
case Type::BLAKE2s_160:
case Type::BLAKE2s_224:
case Type::BLAKE2s_256: return 64;
case Type::BLAKE2b_128:
case Type::BLAKE2b_160:
case Type::BLAKE2b_224:
case Type::BLAKE2b_256:
case Type::BLAKE2b_384:
case Type::BLAKE2b_512: return 128;
default: break;
}
return 0;
}
PIConstChars PIDigest::typeName(Type type) {
switch (type) {
case Type::MD2: return "MD2";
case Type::MD4: return "MD4";
case Type::MD5: return "MD5";
case Type::SHA1: return "SHA1";
case Type::SHA2_224: return "SHA2_224";
case Type::SHA2_256: return "SHA2_256";
case Type::SHA2_384: return "SHA2_384";
case Type::SHA2_512: return "SHA2_512";
case Type::SHA2_512_224: return "SHA2_512_224";
case Type::SHA2_512_256: return "SHA2_512_256";
case Type::BLAKE2s_128: return "BLAKE2s_128";
case Type::BLAKE2s_160: return "BLAKE2s_160";
case Type::BLAKE2s_224: return "BLAKE2s_224";
case Type::BLAKE2s_256: return "BLAKE2s_256";
case Type::BLAKE2b_128: return "BLAKE2b_128";
case Type::BLAKE2b_160: return "BLAKE2b_160";
case Type::BLAKE2b_224: return "BLAKE2b_224";
case Type::BLAKE2b_256: return "BLAKE2b_256";
case Type::BLAKE2b_384: return "BLAKE2b_384";
case Type::BLAKE2b_512: return "BLAKE2b_512";
default: break;
}
return "Unknown";
}
PIByteArray PIDigest::calculate(const PIByteArray & msg, Type type) {
switch (type) {
case Type::MD2: return MD2::md2(msg);
case Type::MD4: return MD4::md4(msg);
case Type::MD5: return MD5::md5(msg);
case Type::SHA1: return SHA1::sha1(msg);
case Type::SHA2_224: return SHA2::sha2xx(msg, SHA2::initial_224, 28);
case Type::SHA2_256: return SHA2::sha2xx(msg, SHA2::initial_256, 32);
case Type::SHA2_384: return SHA2::sha5xx(msg, SHA2::initial_384, 48);
case Type::SHA2_512: return SHA2::sha5xx(msg, SHA2::initial_512, 64);
case Type::SHA2_512_224: return SHA2::sha5xx(msg, SHA2::initial_512_224, 28);
case Type::SHA2_512_256: return SHA2::sha5xx(msg, SHA2::initial_512_256, 32);
case Type::BLAKE2s_128: return BLAKE2::blake2s(msg, 16);
case Type::BLAKE2s_160: return BLAKE2::blake2s(msg, 20);
case Type::BLAKE2s_224: return BLAKE2::blake2s(msg, 28);
case Type::BLAKE2s_256: return BLAKE2::blake2s(msg, 32);
case Type::BLAKE2b_128: return BLAKE2::blake2b(msg, 16);
case Type::BLAKE2b_160: return BLAKE2::blake2b(msg, 20);
case Type::BLAKE2b_224: return BLAKE2::blake2b(msg, 28);
case Type::BLAKE2b_256: return BLAKE2::blake2b(msg, 32);
case Type::BLAKE2b_384: return BLAKE2::blake2b(msg, 48);
case Type::BLAKE2b_512: return BLAKE2::blake2b(msg, 64);
default: break;
}
return {};
}
PIByteArray PIDigest::HMAC(const PIByteArray & msg, const PIByteArray & key, Type type) {
int b = PIDigest::blockLength(type);
auto ipad = PIByteArray(b, uchar(0x36));
auto opad = PIByteArray(b, uchar(0x5C));
PIByteArray k0;
if (key.size_s() > b)
k0 = PIDigest::calculate(key, type);
else
k0 = key;
k0.resize(b);
return PIDigest::calculate((k0 ^ opad).append(PIDigest::calculate((k0 ^ ipad).append(msg), type)), type);
}

View File

@@ -0,0 +1,72 @@
/*! \file pidigest.h
* \ingroup Core
* \~\brief
* \~english Digest algorithms
* \~russian Алгоритмы хэш-сумм
*
* \~\details
* \~english
* This file implements several common-usage hash algorithms
* \~russian
* Этот файл реализует несколько распространенных алгоритмов хэширования
*/
/*
PIP - Platform Independent Primitives
Digest algorithms
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef pidigest_h
#define pidigest_h
#include "pibytearray.h"
#include "piconstchars.h"
class PIP_EXPORT PIDigest {
public:
enum class Type {
SHA1,
SHA2_224,
SHA2_256,
SHA2_384,
SHA2_512,
SHA2_512_224,
SHA2_512_256,
MD2,
MD4,
MD5,
BLAKE2s_128,
BLAKE2s_160,
BLAKE2s_224,
BLAKE2s_256,
BLAKE2b_128,
BLAKE2b_160,
BLAKE2b_224,
BLAKE2b_256,
BLAKE2b_384,
BLAKE2b_512,
Count,
};
static int hashLength(Type type);
static int blockLength(Type type);
static PIConstChars typeName(Type type);
static PIByteArray calculate(const PIByteArray & msg, Type type);
static PIByteArray HMAC(const PIByteArray & msg, const PIByteArray & key, PIDigest::Type type);
};
#endif

View File

@@ -0,0 +1,64 @@
/*
PIP - Platform Independent Primitives
Digest algorithms
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pidigest_blake2_p.h"
#include "3rd/BLAKE2/blake2.h"
PIByteArray BLAKE2::blake2s(const PIByteArray & in, int out_bytes) {
PIByteArray ret(out_bytes);
::blake2s(ret.data(), ret.size(), in.data(), in.size(), nullptr, 0);
return ret;
}
PIByteArray BLAKE2::blake2b(const PIByteArray & in, int out_bytes) {
PIByteArray ret(out_bytes);
::blake2b(ret.data(), ret.size(), in.data(), in.size(), nullptr, 0);
return ret;
}
PIByteArray BLAKE2::blake2sp(const PIByteArray & in, int out_bytes) {
PIByteArray ret(out_bytes);
::blake2sp(ret.data(), ret.size(), in.data(), in.size(), nullptr, 0);
return ret;
}
PIByteArray BLAKE2::blake2bp(const PIByteArray & in, int out_bytes) {
PIByteArray ret(out_bytes);
::blake2bp(ret.data(), ret.size(), in.data(), in.size(), nullptr, 0);
return ret;
}
PIByteArray BLAKE2::blake2xs(const PIByteArray & in, int out_bytes) {
PIByteArray ret(out_bytes);
::blake2xs(ret.data(), ret.size(), in.data(), in.size(), nullptr, 0);
return ret;
}
PIByteArray BLAKE2::blake2xb(const PIByteArray & in, int out_bytes) {
PIByteArray ret(out_bytes);
::blake2xb(ret.data(), ret.size(), in.data(), in.size(), nullptr, 0);
return ret;
}

View File

@@ -0,0 +1,35 @@
/*
PIP - Platform Independent Primitives
Digest algorithms
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef pidigest_blake2_h
#define pidigest_blake2_h
#include "pibytearray.h"
class BLAKE2 {
public:
static PIByteArray blake2s(const PIByteArray & in, int out_bytes);
static PIByteArray blake2b(const PIByteArray & in, int out_bytes);
static PIByteArray blake2sp(const PIByteArray & in, int out_bytes);
static PIByteArray blake2bp(const PIByteArray & in, int out_bytes);
static PIByteArray blake2xs(const PIByteArray & in, int out_bytes);
static PIByteArray blake2xb(const PIByteArray & in, int out_bytes);
};
#endif

View File

@@ -0,0 +1,88 @@
/*
PIP - Platform Independent Primitives
Digest algorithms
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pidigest_md2_p.h"
PIByteArray MD2::md2(const PIByteArray & in) {
constexpr int part_size = 16;
static constexpr uchar S[] = {
41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6, 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147,
43, 217, 188, 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24, 138, 23, 229, 18, 190, 78, 196, 214,
218, 158, 222, 73, 160, 251, 245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63, 148, 194, 16, 137, 11, 34,
95, 33, 128, 127, 93, 154, 90, 144, 50, 39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165, 181, 209,
215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210, 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157,
112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27, 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105,
52, 64, 126, 15, 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197, 234, 38, 44, 83, 13, 110, 133, 40,
132, 9, 211, 223, 205, 244, 65, 129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123, 8, 12, 189, 177, 74,
120, 136, 149, 139, 227, 99, 232, 109, 233, 203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228, 166, 119,
114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237, 31, 26, 219, 153, 141, 51, 159, 17, 131, 20};
PIByteArray msg = in;
int add_l = part_size - (msg.size() % part_size);
if (add_l <= 0) add_l += part_size;
for (int i = 0; i < add_l; ++i)
msg.append(uchar(add_l));
int parts = msg.size_s() / part_size;
// piCout << "add" << add_l << "=" << (in.size() + add_l) << msg.size() << parts;
uchar cs[16];
for (int i = 0; i < 16; ++i)
cs[i] = 0;
uchar l = 0;
for (int p = 0; p < parts; ++p) {
uchar * mb = (uchar *)msg.data(p * part_size);
for (int j = 0; j < 16; ++j) {
uchar c = mb[j];
cs[j] = cs[j] ^ S[c ^ l];
l = cs[j];
}
}
msg.append(cs, 16);
++parts;
uchar x[48];
for (int i = 0; i < 48; ++i)
x[i] = 0;
for (int p = 0; p < parts; ++p) {
uchar * mb = (uchar *)msg.data(p * part_size);
for (int j = 0; j < 16; ++j) {
uchar c = mb[j];
cs[j] = cs[j] ^ S[c ^ l];
l = cs[j];
}
for (int j = 0; j < 16; ++j) {
x[16 + j] = mb[j];
x[32 + j] = (x[16 + j] ^ x[j]);
}
uchar t = 0;
for (int j = 0; j < 18; ++j) {
for (int k = 0; k < 48; ++k) {
t = x[k] = (x[k] ^ S[t]);
}
t = (t + j) % 256;
}
}
return PIByteArray(x, 16);
}

View File

@@ -0,0 +1,30 @@
/*
PIP - Platform Independent Primitives
Digest algorithms
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef pidigest_md2_h
#define pidigest_md2_h
#include "pibytearray.h"
class MD2 {
public:
static PIByteArray md2(const PIByteArray & in);
};
#endif

View File

@@ -0,0 +1,127 @@
/*
PIP - Platform Independent Primitives
Digest algorithms
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pidigest_md4_p.h"
template<typename T>
inline T rotate_u(T v, int bits) {
return (v << bits) | (v >> ((sizeof(T) * 8) - bits));
}
#define F(X, Y, Z) (((X) & (Y)) | ((~(X)) & (Z)))
#define G(X, Y, Z) (((X) & (Y)) | ((X) & (Z)) | ((Y) & (Z)))
#define H(X, Y, Z) ((X) ^ (Y) ^ (Z))
#define MD4ROUND1(a, b, c, d, x, s) \
a += F(b, c, d) + x; \
a = rotate_u(a, s);
#define MD4ROUND2(a, b, c, d, x, s) \
a += G(b, c, d) + x + 0x5A827999u; \
a = rotate_u(a, s);
#define MD4ROUND3(a, b, c, d, x, s) \
a += H(b, c, d) + x + 0x6ED9EBA1u; \
a = rotate_u(a, s);
PIByteArray MD4::md4(const PIByteArray & in) {
constexpr int part_size = 64;
uint32_t a = piChangedEndian(0x01234567u);
uint32_t b = piChangedEndian(0x89ABCDEFu);
uint32_t c = piChangedEndian(0xFEDCBA98u);
uint32_t d = piChangedEndian(0x76543210u);
uint64_t l = in.size() * 8;
PIByteArray msg = in;
int add_l = (part_size - 8) - (msg.size() % (part_size));
if (add_l <= 0) add_l += part_size;
msg.append(0x80);
for (int i = 1; i < add_l; ++i)
msg.append(0x0);
msg << l;
int parts = msg.size_s() / part_size;
// piCout << l << "add" << add_l << "=" << (in.size() + add_l + sizeof(l)) << msg.size() << parts;
for (int p = 0; p < parts; ++p) {
uint32_t * mw = (uint32_t *)msg.data(p * part_size);
// piCout << PIByteArray(w, 64);
uint32_t a0 = a;
uint32_t b0 = b;
uint32_t c0 = c;
uint32_t d0 = d;
MD4ROUND1(a, b, c, d, mw[0], 3);
MD4ROUND1(d, a, b, c, mw[1], 7);
MD4ROUND1(c, d, a, b, mw[2], 11);
MD4ROUND1(b, c, d, a, mw[3], 19);
MD4ROUND1(a, b, c, d, mw[4], 3);
MD4ROUND1(d, a, b, c, mw[5], 7);
MD4ROUND1(c, d, a, b, mw[6], 11);
MD4ROUND1(b, c, d, a, mw[7], 19);
MD4ROUND1(a, b, c, d, mw[8], 3);
MD4ROUND1(d, a, b, c, mw[9], 7);
MD4ROUND1(c, d, a, b, mw[10], 11);
MD4ROUND1(b, c, d, a, mw[11], 19);
MD4ROUND1(a, b, c, d, mw[12], 3);
MD4ROUND1(d, a, b, c, mw[13], 7);
MD4ROUND1(c, d, a, b, mw[14], 11);
MD4ROUND1(b, c, d, a, mw[15], 19);
MD4ROUND2(a, b, c, d, mw[0], 3);
MD4ROUND2(d, a, b, c, mw[4], 5);
MD4ROUND2(c, d, a, b, mw[8], 9);
MD4ROUND2(b, c, d, a, mw[12], 13);
MD4ROUND2(a, b, c, d, mw[1], 3);
MD4ROUND2(d, a, b, c, mw[5], 5);
MD4ROUND2(c, d, a, b, mw[9], 9);
MD4ROUND2(b, c, d, a, mw[13], 13);
MD4ROUND2(a, b, c, d, mw[2], 3);
MD4ROUND2(d, a, b, c, mw[6], 5);
MD4ROUND2(c, d, a, b, mw[10], 9);
MD4ROUND2(b, c, d, a, mw[14], 13);
MD4ROUND2(a, b, c, d, mw[3], 3);
MD4ROUND2(d, a, b, c, mw[7], 5);
MD4ROUND2(c, d, a, b, mw[11], 9);
MD4ROUND2(b, c, d, a, mw[15], 13);
MD4ROUND3(a, b, c, d, mw[0], 3);
MD4ROUND3(d, a, b, c, mw[8], 9);
MD4ROUND3(c, d, a, b, mw[4], 11);
MD4ROUND3(b, c, d, a, mw[12], 15);
MD4ROUND3(a, b, c, d, mw[2], 3);
MD4ROUND3(d, a, b, c, mw[10], 9);
MD4ROUND3(c, d, a, b, mw[6], 11);
MD4ROUND3(b, c, d, a, mw[14], 15);
MD4ROUND3(a, b, c, d, mw[1], 3);
MD4ROUND3(d, a, b, c, mw[9], 9);
MD4ROUND3(c, d, a, b, mw[5], 11);
MD4ROUND3(b, c, d, a, mw[13], 15);
MD4ROUND3(a, b, c, d, mw[3], 3);
MD4ROUND3(d, a, b, c, mw[11], 9);
MD4ROUND3(c, d, a, b, mw[7], 11);
MD4ROUND3(b, c, d, a, mw[15], 15);
a += a0;
b += b0;
c += c0;
d += d0;
}
PIByteArray ret;
ret << a << b << c << d;
return ret;
}

View File

@@ -0,0 +1,30 @@
/*
PIP - Platform Independent Primitives
Digest algorithms
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef pidigest_md4_h
#define pidigest_md4_h
#include "pibytearray.h"
class MD4 {
public:
static PIByteArray md4(const PIByteArray & in);
};
#endif

View File

@@ -0,0 +1,93 @@
/*
PIP - Platform Independent Primitives
Digest algorithms
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pidigest_md5_p.h"
template<typename T>
inline T rotate_u(T v, int bits) {
return (v << bits) | (v >> ((sizeof(T) * 8) - bits));
}
PIByteArray MD5::md5(const PIByteArray & in) {
constexpr int part_size = 64;
static constexpr uint32_t K[64] = {
0xD76AA478u, 0xE8C7B756u, 0x242070DBu, 0xC1BDCEEEu, 0xF57C0FAFu, 0x4787C62Au, 0xA8304613u, 0xFD469501u, 0x698098D8u, 0x8B44F7AFu,
0xFFFF5BB1u, 0x895CD7BEu, 0x6B901122u, 0xFD987193u, 0xA679438Eu, 0x49B40821u, 0xF61E2562u, 0xC040B340u, 0x265E5A51u, 0xE9B6C7AAu,
0xD62F105Du, 0x02441453u, 0xD8A1E681u, 0xE7D3FBC8u, 0x21E1CDE6u, 0xC33707D6u, 0xF4D50D87u, 0x455A14EDu, 0xA9E3E905u, 0xFCEFA3F8u,
0x676F02D9u, 0x8D2A4C8Au, 0xFFFA3942u, 0x8771F681u, 0x6D9D6122u, 0xFDE5380Cu, 0xA4BEEA44u, 0x4BDECFA9u, 0xF6BB4B60u, 0xBEBFBC70u,
0x289B7EC6u, 0xEAA127FAu, 0xD4EF3085u, 0x04881D05u, 0xD9D4D039u, 0xE6DB99E5u, 0x1FA27CF8u, 0xC4AC5665u, 0xF4292244u, 0x432AFF97u,
0xAB9423A7u, 0xFC93A039u, 0x655B59C3u, 0x8F0CCC92u, 0xFFEFF47Du, 0x85845DD1u, 0x6FA87E4Fu, 0xFE2CE6E0u, 0xA3014314u, 0x4E0811A1u,
0xF7537E82u, 0xBD3AF235u, 0x2AD7D2BBu, 0xEB86D391u};
static constexpr uint32_t s[64] = {7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, 9,
14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
4, 11, 16, 23, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21};
uint32_t a0 = 0x67452301u;
uint32_t b0 = 0xefcdab89u;
uint32_t c0 = 0x98badcfeu;
uint32_t d0 = 0x10325476u;
uint64_t l = in.size() * 8;
PIByteArray msg = in;
int add_l = (part_size - 8) - (msg.size() % (part_size));
if (add_l <= 0) add_l += part_size;
msg.append(0x80);
for (int i = 1; i < add_l; ++i)
msg.append(0x0);
msg << l;
int parts = msg.size_s() / part_size;
// piCout << l << "add" << add_l << "=" << (in.size() + add_l + sizeof(l)) << msg.size() << parts;
for (int p = 0; p < parts; ++p) {
uint32_t * mw = (uint32_t *)msg.data(p * part_size);
uint32_t A = a0;
uint32_t B = b0;
uint32_t C = c0;
uint32_t D = d0;
for (int i = 0; i < 64; ++i) {
uint32_t F = 0, g = 0;
if (i >= 0 && i <= 15) {
F = (B & C) | ((~B) & D);
g = i;
} else if (i >= 16 && i <= 31) {
F = (D & B) | ((~D) & C);
g = (5 * i + 1) % 16;
} else if (i >= 32 && i <= 47) {
F = B ^ C ^ D;
g = (3 * i + 5) % 16;
} else if (i >= 48 && i <= 63) {
F = C ^ (B | (~D));
g = (7 * i) % 16;
}
F = F + A + K[i] + mw[g];
A = D;
D = C;
C = B;
B = B + rotate_u(F, s[i]);
}
a0 = a0 + A;
b0 = b0 + B;
c0 = c0 + C;
d0 = d0 + D;
}
PIByteArray ret;
ret << a0 << b0 << c0 << d0;
return ret;
}

View File

@@ -0,0 +1,30 @@
/*
PIP - Platform Independent Primitives
Digest algorithms
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef pidigest_md5_h
#define pidigest_md5_h
#include "pibytearray.h"
class MD5 {
public:
static PIByteArray md5(const PIByteArray & in);
};
#endif

View File

@@ -0,0 +1,98 @@
/*
PIP - Platform Independent Primitives
Digest algorithms
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pidigest_sha1_p.h"
template<typename T>
inline T rotate_u(T v, int bits) {
return (v << bits) | (v >> ((sizeof(T) * 8) - bits));
}
template<typename T>
inline T shift_u(T v, int bits) {
return v << bits;
}
PIByteArray SHA1::sha1(const PIByteArray & in) {
constexpr int part_size = 64;
constexpr int rounds = 80;
uint32_t h0 = 0x67452301u;
uint32_t h1 = 0xEFCDAB89u;
uint32_t h2 = 0x98BADCFEu;
uint32_t h3 = 0x10325476u;
uint32_t h4 = 0xC3D2E1F0u;
uint64_t l = in.size() * 8;
PIByteArray msg = in;
int add_l = (part_size - 8) - (msg.size() % (part_size));
if (add_l <= 0) add_l += part_size;
msg.append(0x80);
for (int i = 1; i < add_l; ++i)
msg.append(0x0);
msg << piChangedEndian(l);
int parts = msg.size_s() / part_size;
// piCout << l << "add" << add_l << "=" << (in.size() + add_l + sizeof(l)) << msg.size() << parts;
uint32_t w[80];
for (int p = 0; p < parts; ++p) {
uint32_t * mw = (uint32_t *)msg.data(p * part_size);
for (int i = 0; i < 16; ++i)
w[i] = piChangedEndian(mw[i]);
for (int i = 16; i < 80; ++i) {
w[i] = rotate_u((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]), 1);
}
uint32_t a = h0;
uint32_t b = h1;
uint32_t c = h2;
uint32_t d = h3;
uint32_t e = h4;
uint32_t f = 0;
uint32_t k = 0;
uint32_t t = 0;
for (int i = 0; i < rounds; ++i) {
if (i >= 0 && i <= 19) {
f = (b & c) | ((~b) & d);
k = 0x5A827999;
} else if (i >= 20 && i <= 39) {
f = b ^ c ^ d;
k = 0x6ED9EBA1;
} else if (i >= 40 && i <= 59) {
f = (b & c) | (b & d) | (c & d);
k = 0x8F1BBCDC;
} else if (i >= 60 && i <= 79) {
f = b ^ c ^ d;
k = 0xCA62C1D6;
}
t = rotate_u(a, 5) + f + e + k + w[i];
e = d;
d = c;
c = rotate_u(b, 30);
b = a;
a = t;
}
h0 += a;
h1 += b;
h2 += c;
h3 += d;
h4 += e;
}
PIByteArray ret;
ret << piChangedEndian(h0) << piChangedEndian(h1) << piChangedEndian(h2) << piChangedEndian(h3) << piChangedEndian(h4);
return ret;
}

View File

@@ -0,0 +1,30 @@
/*
PIP - Platform Independent Primitives
Digest algorithms
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef pidigest_sha1_h
#define pidigest_sha1_h
#include "pibytearray.h"
class SHA1 {
public:
static PIByteArray sha1(const PIByteArray & in);
};
#endif

View File

@@ -0,0 +1,240 @@
/*
PIP - Platform Independent Primitives
Digest algorithms
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pidigest_sha2_p.h"
const uint32_t SHA2::initial_224[8] =
{0xC1059ED8u, 0x367CD507u, 0x3070DD17u, 0xF70E5939u, 0xFFC00B31u, 0x68581511u, 0x64F98FA7u, 0xBEFA4FA4u};
const uint32_t SHA2::initial_256[8] =
{0x6A09E667u, 0xBB67AE85u, 0x3C6EF372u, 0xA54FF53Au, 0x510E527Fu, 0x9B05688Cu, 0x1F83D9ABu, 0x5BE0CD19u};
const uint64_t SHA2::initial_384[8] = {0xCBBB9D5DC1059ED8U,
0x629A292A367CD507U,
0x9159015A3070DD17U,
0x152FECD8F70E5939U,
0x67332667FFC00B31U,
0x8EB44A8768581511U,
0xDB0C2E0D64F98FA7U,
0x47B5481DBEFA4FA4U};
const uint64_t SHA2::initial_512[8] = {0X6A09E667F3BCC908U,
0XBB67AE8584CAA73BU,
0X3C6EF372FE94F82BU,
0XA54FF53A5F1D36F1U,
0X510E527FADE682D1U,
0X9B05688C2B3E6C1FU,
0X1F83D9ABFB41BD6BU,
0X5BE0CD19137E2179U};
const uint64_t SHA2::initial_512_256[8] = {0x22312194FC2BF72CU,
0x9F555FA3C84C64C2U,
0x2393B86B6F53B151U,
0x963877195940EABDU,
0x96283EE2A88EFFE3U,
0xBE5E1E2553863992U,
0x2B0199FC2C85B8AAU,
0x0EB72DDC81C52CA2U};
const uint64_t SHA2::initial_512_224[8] = {0x8C3D37C819544DA2U,
0x73E1996689DCD4D6U,
0x1DFAB7AE32FF9C82U,
0x679DD514582F9FCFU,
0x0F6D2B697BD44DA8U,
0x77E36F7304C48942U,
0x3F9D85A86A1D36C8U,
0x1112E6AD91D692A1U};
template<typename T>
inline T rotate_u(T v, int bits) {
return (v >> bits) | (v << ((sizeof(T) * 8) - bits));
}
template<typename T>
inline T shift_u(T v, int bits) {
return v >> bits;
}
PIByteArray SHA2::sha2xx(const PIByteArray & in, const uint32_t * initial, int out_bytes) {
constexpr int part_size = 64;
constexpr int rounds = 64;
static constexpr uint32_t k[part_size] = {
0x428A2F98u, 0x71374491u, 0xB5C0FBCFu, 0xE9B5DBA5u, 0x3956C25Bu, 0x59F111F1u, 0x923F82A4u, 0xAB1C5ED5u, 0xD807AA98u, 0x12835B01u,
0x243185BEu, 0x550C7DC3u, 0x72BE5D74u, 0x80DEB1FEu, 0x9BDC06A7u, 0xC19BF174u, 0xE49B69C1u, 0xEFBE4786u, 0x0FC19DC6u, 0x240CA1CCu,
0x2DE92C6Fu, 0x4A7484AAu, 0x5CB0A9DCu, 0x76F988DAu, 0x983E5152u, 0xA831C66Du, 0xB00327C8u, 0xBF597FC7u, 0xC6E00BF3u, 0xD5A79147u,
0x06CA6351u, 0x14292967u, 0x27B70A85u, 0x2E1B2138u, 0x4D2C6DFCu, 0x53380D13u, 0x650A7354u, 0x766A0ABBu, 0x81C2C92Eu, 0x92722C85u,
0xA2BFE8A1u, 0xA81A664Bu, 0xC24B8B70u, 0xC76C51A3u, 0xD192E819u, 0xD6990624u, 0xF40E3585u, 0x106AA070u, 0x19A4C116u, 0x1E376C08u,
0x2748774Cu, 0x34B0BCB5u, 0x391C0CB3u, 0x4ED8AA4Au, 0x5B9CCA4Fu, 0x682E6FF3u, 0x748F82EEu, 0x78A5636Fu, 0x84C87814u, 0x8CC70208u,
0x90BEFFFAu, 0xA4506CEBu, 0xBEF9A3F7u, 0xC67178F2u};
uint32_t h0 = initial[0];
uint32_t h1 = initial[1];
uint32_t h2 = initial[2];
uint32_t h3 = initial[3];
uint32_t h4 = initial[4];
uint32_t h5 = initial[5];
uint32_t h6 = initial[6];
uint32_t h7 = initial[7];
uint64_t l = in.size() * 8;
PIByteArray msg = in;
int add_l = (part_size - 8) - (msg.size() % (part_size));
if (add_l <= 0) add_l += part_size;
msg.append(0x80);
for (int i = 1; i < add_l; ++i)
msg.append(0x0);
msg << piChangedEndian(l);
int parts = msg.size_s() / part_size;
// piCout << l << "add" << add_l << "=" << (in.size() + add_l + sizeof(l)) << msg.size() << parts;
uint32_t w[64];
for (int p = 0; p < parts; ++p) {
uint32_t * mw = (uint32_t *)msg.data(p * part_size);
for (int i = 0; i < 16; ++i)
w[i] = piChangedEndian(mw[i]);
for (int i = 16; i < 64; ++i) {
uint32_t s0 = rotate_u(w[i - 15], 7) ^ rotate_u(w[i - 15], 18) ^ shift_u(w[i - 15], 3);
uint32_t s1 = rotate_u(w[i - 2], 17) ^ rotate_u(w[i - 2], 19) ^ shift_u(w[i - 2], 10);
w[i] = w[i - 16] + s0 + w[i - 7] + s1;
}
uint32_t a = h0;
uint32_t b = h1;
uint32_t c = h2;
uint32_t d = h3;
uint32_t e = h4;
uint32_t f = h5;
uint32_t g = h6;
uint32_t h = h7;
for (int i = 0; i < rounds; ++i) {
uint32_t S1 = rotate_u(e, 6) ^ rotate_u(e, 11) ^ rotate_u(e, 25);
uint32_t ch = (e & f) ^ (~e & g);
uint32_t t1 = h + S1 + ch + k[i] + w[i];
uint32_t S0 = rotate_u(a, 2) ^ rotate_u(a, 13) ^ rotate_u(a, 22);
uint32_t maj = (a & b) ^ (a & c) ^ (b & c);
uint32_t t2 = S0 + maj;
h = g;
g = f;
f = e;
e = d + t1;
d = c;
c = b;
b = a;
a = t1 + t2;
}
h0 += a;
h1 += b;
h2 += c;
h3 += d;
h4 += e;
h5 += f;
h6 += g;
h7 += h;
}
PIByteArray ret;
ret << piChangedEndian(h0) << piChangedEndian(h1) << piChangedEndian(h2) << piChangedEndian(h3) << piChangedEndian(h4)
<< piChangedEndian(h5) << piChangedEndian(h6) << piChangedEndian(h7);
ret.resize(out_bytes);
return ret;
}
PIByteArray SHA2::sha5xx(const PIByteArray & in, const uint64_t * initial, int out_bytes) {
constexpr int part_size = 128;
constexpr int rounds = 80;
static constexpr uint64_t k[80] = {
0X428A2F98D728AE22U, 0X7137449123EF65CDU, 0XB5C0FBCFEC4D3B2FU, 0XE9B5DBA58189DBBCU, 0X3956C25BF348B538U, 0X59F111F1B605D019U,
0X923F82A4AF194F9BU, 0XAB1C5ED5DA6D8118U, 0XD807AA98A3030242U, 0X12835B0145706FBEU, 0X243185BE4EE4B28CU, 0X550C7DC3D5FFB4E2U,
0X72BE5D74F27B896FU, 0X80DEB1FE3B1696B1U, 0X9BDC06A725C71235U, 0XC19BF174CF692694U, 0XE49B69C19EF14AD2U, 0XEFBE4786384F25E3U,
0X0FC19DC68B8CD5B5U, 0X240CA1CC77AC9C65U, 0X2DE92C6F592B0275U, 0X4A7484AA6EA6E483U, 0X5CB0A9DCBD41FBD4U, 0X76F988DA831153B5U,
0X983E5152EE66DFABU, 0XA831C66D2DB43210U, 0XB00327C898FB213FU, 0XBF597FC7BEEF0EE4U, 0XC6E00BF33DA88FC2U, 0XD5A79147930AA725U,
0X06CA6351E003826FU, 0X142929670A0E6E70U, 0X27B70A8546D22FFCU, 0X2E1B21385C26C926U, 0X4D2C6DFC5AC42AEDU, 0X53380D139D95B3DFU,
0X650A73548BAF63DEU, 0X766A0ABB3C77B2A8U, 0X81C2C92E47EDAEE6U, 0X92722C851482353BU, 0XA2BFE8A14CF10364U, 0XA81A664BBC423001U,
0XC24B8B70D0F89791U, 0XC76C51A30654BE30U, 0XD192E819D6EF5218U, 0XD69906245565A910U, 0XF40E35855771202AU, 0X106AA07032BBD1B8U,
0X19A4C116B8D2D0C8U, 0X1E376C085141AB53U, 0X2748774CDF8EEB99U, 0X34B0BCB5E19B48A8U, 0X391C0CB3C5C95A63U, 0X4ED8AA4AE3418ACBU,
0X5B9CCA4F7763E373U, 0X682E6FF3D6B2B8A3U, 0X748F82EE5DEFB2FCU, 0X78A5636F43172F60U, 0X84C87814A1F0AB72U, 0X8CC702081A6439ECU,
0X90BEFFFA23631E28U, 0XA4506CEBDE82BDE9U, 0XBEF9A3F7B2C67915U, 0XC67178F2E372532BU, 0XCA273ECEEA26619CU, 0XD186B8C721C0C207U,
0XEADA7DD6CDE0EB1EU, 0XF57D4F7FEE6ED178U, 0X06F067AA72176FBAU, 0X0A637DC5A2C898A6U, 0X113F9804BEF90DAEU, 0X1B710B35131C471BU,
0X28DB77F523047D84U, 0X32CAAB7B40C72493U, 0X3C9EBE0A15C9BEBCU, 0X431D67C49C100D4CU, 0X4CC5D4BECB3E42B6U, 0X597F299CFC657E2AU,
0X5FCB6FAB3AD6FAECU, 0X6C44198C4A475817U};
uint64_t h0 = initial[0];
uint64_t h1 = initial[1];
uint64_t h2 = initial[2];
uint64_t h3 = initial[3];
uint64_t h4 = initial[4];
uint64_t h5 = initial[5];
uint64_t h6 = initial[6];
uint64_t h7 = initial[7];
uint64_t l = in.size() * 8;
PIByteArray msg = in;
int add_l = (part_size - 8) - (msg.size() % (part_size));
if (add_l <= 0) add_l += part_size;
msg.append(0x80);
for (int i = 1; i < add_l; ++i)
msg.append(0x0);
msg << piChangedEndian(l);
int parts = msg.size_s() / part_size;
// piCout << l << "add" << add_l << "=" << (in.size() + add_l + sizeof(l)) << msg.size() << parts;
uint64_t w[80];
for (int p = 0; p < parts; ++p) {
uint64_t * mw = (uint64_t *)msg.data(p * part_size);
for (int i = 0; i < 16; ++i)
w[i] = piChangedEndian(mw[i]);
for (int i = 16; i < 80; ++i) {
uint64_t s0 = rotate_u(w[i - 15], 1) ^ rotate_u(w[i - 15], 8) ^ shift_u(w[i - 15], 7);
uint64_t s1 = rotate_u(w[i - 2], 19) ^ rotate_u(w[i - 2], 61) ^ shift_u(w[i - 2], 6);
w[i] = w[i - 16] + s0 + w[i - 7] + s1;
}
uint64_t a = h0;
uint64_t b = h1;
uint64_t c = h2;
uint64_t d = h3;
uint64_t e = h4;
uint64_t f = h5;
uint64_t g = h6;
uint64_t h = h7;
for (int i = 0; i < rounds; ++i) {
uint64_t S1 = rotate_u(e, 14) ^ rotate_u(e, 18) ^ rotate_u(e, 41);
uint64_t ch = (e & f) ^ (~e & g);
uint64_t t1 = h + S1 + ch + k[i] + w[i];
uint64_t S0 = rotate_u(a, 28) ^ rotate_u(a, 34) ^ rotate_u(a, 39);
uint64_t maj = (a & b) ^ (a & c) ^ (b & c);
uint64_t t2 = S0 + maj;
h = g;
g = f;
f = e;
e = d + t1;
d = c;
c = b;
b = a;
a = t1 + t2;
}
h0 += a;
h1 += b;
h2 += c;
h3 += d;
h4 += e;
h5 += f;
h6 += g;
h7 += h;
}
PIByteArray ret;
ret << piChangedEndian(h0) << piChangedEndian(h1) << piChangedEndian(h2) << piChangedEndian(h3) << piChangedEndian(h4)
<< piChangedEndian(h5) << piChangedEndian(h6) << piChangedEndian(h7);
ret.resize(out_bytes);
return ret;
}

View File

@@ -0,0 +1,39 @@
/*
PIP - Platform Independent Primitives
Digest algorithms
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef pidigest_sha2_h
#define pidigest_sha2_h
#include "pibytearray.h"
class SHA2 {
public:
static const uint32_t initial_224[8];
static const uint32_t initial_256[8];
static const uint64_t initial_384[8];
static const uint64_t initial_512[8];
static const uint64_t initial_512_256[8];
static const uint64_t initial_512_224[8];
static PIByteArray sha2xx(const PIByteArray & in, const uint32_t * initial, int out_bytes);
static PIByteArray sha5xx(const PIByteArray & in, const uint64_t * initial, int out_bytes);
};
#endif

View File

@@ -24,6 +24,24 @@ PIHTTP::MessageMutable & PIHTTP::MessageMutable::addHeader(const PIString & head
}
PIHTTP::MessageMutable & PIHTTP::MessageMutable::removeHeader(const PIString & header) {
m_headers.remove(header);
return *this;
}
PIHTTP::MessageMutable & PIHTTP::MessageMutable::addArgument(const PIString & arg, const PIString & value) {
m_arguments[arg] = value;
return *this;
}
PIHTTP::MessageMutable & PIHTTP::MessageMutable::removeArgument(const PIString & arg) {
m_arguments.remove(arg);
return *this;
}
PIHTTP::MessageMutable & PIHTTP::MessageMutable::setMethod(Method m) {
m_method = m;
return *this;

View File

@@ -37,9 +37,11 @@ public:
const PIMap<PIString, PIString> & headers() const { return m_headers; }
const PIMap<PIString, PIString> & arguments() const { return m_arguments; }
PIMap<PIString, PIString> & headers() { return m_headers; }
PIMap<PIString, PIString> & arguments() { return m_arguments; }
MessageMutable & addHeader(const PIString & header, const PIString & value);
void removeHeader(const PIString & header) { m_headers.remove(header); }
MessageMutable & removeHeader(const PIString & header);
PIMap<PIString, PIString> & arguments() { return m_arguments; }
MessageMutable & addArgument(const PIString & arg, const PIString & value);
MessageMutable & removeArgument(const PIString & arg);
static MessageMutable fromCode(PIHTTP::Code c);
static MessageMutable fromMethod(PIHTTP::Method m);
};

View File

@@ -26,6 +26,7 @@
#include "picontainersmodule.h"
#include "picoremodule.h"
#include "picryptmodule.h"
#include "pidigest.h"
#include "pigeomodule.h"
#include "pihttpservermodule.h"
#include "piiodevicesmodule.h"

View File

@@ -1810,6 +1810,46 @@ PIString & PIString::setReadableSize(llong bytes) {
}
PIString PIString::toPercentageEncoding() const {
static const PIString valid = "-._~"_a;
PIString ret;
PIByteArray utf8;
bool ok = false;
for (const auto & c: *this) {
ok = false;
if (c.isAscii()) {
if (c.isAlpha() || c.isDigit())
ok = true;
else if (valid.contains(c))
ok = true;
}
if (ok) {
ret.append(c);
} else {
utf8 = PIString(c).toUTF8();
for (auto u: utf8)
ret.append('%').append(PIString::fromNumber(u, 16).expandLeftTo(2, '0'));
}
}
return ret;
}
PIString PIString::fromPercentageEncoding(const PIString & in) {
PIByteArray utf8;
PIChar c;
for (int i = 0; i < in.size_s(); ++i) {
c = in[i];
if (c == '%') {
utf8 << static_cast<uchar>(in.mid(i + 1, 2).toInt(16));
i += 2;
} else
utf8 << static_cast<uchar>(c.toAscii());
}
return PIString::fromUTF8(utf8);
}
PIString & PIString::arg(const PIString & v) {
auto ph = minArgPlaceholder();
if (!ph.isEmpty()) replaceAll(ph, v);

View File

@@ -1687,6 +1687,10 @@ public:
PIString & setReadableSize(llong bytes);
//! \~english Returns [percentage-encoded](https://en.wikipedia.org/wiki/Percent-encoding) string.
//! \~russian Возвращает [URL-кодированную](https://ru.wikipedia.org/wiki/URL) строку.
PIString toPercentageEncoding() const;
//! \~english Replace all occurances like "%1", "%2", ... with lowest value to "v" and returns this string.
//! \~russian Заменяет все вхождения типа "%1", "%2", ... с наименьшим значением на "v" и возвращает эту строку.
//! \~\details
@@ -1906,6 +1910,10 @@ public:
//! \~\sa PIString::setReadableSize()
static PIString readableSize(llong bytes);
//! \~english Returns string from [percentage-encoded](https://en.wikipedia.org/wiki/Percent-encoding) "in".
//! \~russian Возвращает строку из [URL-кодированной](https://ru.wikipedia.org/wiki/URL)"in".
static PIString fromPercentageEncoding(const PIString & in);
//! \~english Swaps string `str` other with this string.
//! \~russian Меняет строку `str` с этой строкой.
//! \~\details
@@ -2020,4 +2028,15 @@ inline void piSwap(PIString & f, PIString & s) {
f.swap(s);
}
//! \~english Returns string representation of \"v\", using PICout operator<<(T)
//! \~russian Возвращает строковое представление \"v\", используя PICout operator<<(T)
template<typename T>
inline PIString piStringify(const T & v) {
PIString ret;
PICout::withExternalBuffer(&ret) << v;
return ret;
}
#endif // PISTRING_H

View File

@@ -1238,6 +1238,39 @@ inline bool operator!=(const PIByteArray & v0, const PIByteArray & v1) {
return true;
}
//! \relatesalso PIByteArray
//! \~english Returns bit-wise "and". If non-equal size, then returns empty %PIByteArray.
//! \~russian Возвращает по-битовое "и" Если размеры не совпадают, возвращает пустой %PIByteArray.
inline PIByteArray operator&(const PIByteArray & v0, const PIByteArray & v1) {
if (v0.size() != v1.size()) return {};
PIByteArray ret(v0.size(), 0);
for (uint i = 0; i < v0.size(); ++i)
ret[i] = v0[i] & v1[i];
return ret;
}
//! \relatesalso PIByteArray
//! \~english Returns bit-wise "or". If non-equal size, then returns empty %PIByteArray.
//! \~russian Возвращает по-битовое "или" Если размеры не совпадают, возвращает пустой %PIByteArray.
inline PIByteArray operator|(const PIByteArray & v0, const PIByteArray & v1) {
if (v0.size() != v1.size()) return {};
PIByteArray ret(v0.size(), 0);
for (uint i = 0; i < v0.size(); ++i)
ret[i] = v0[i] | v1[i];
return ret;
}
//! \relatesalso PIByteArray
//! \~english Returns bit-wise "xor". If non-equal size, then returns empty %PIByteArray.
//! \~russian Возвращает по-битовое "исключающее или" Если размеры не совпадают, возвращает пустой %PIByteArray.
inline PIByteArray operator^(const PIByteArray & v0, const PIByteArray & v1) {
if (v0.size() != v1.size()) return {};
PIByteArray ret(v0.size(), 0);
for (uint i = 0; i < v0.size(); ++i)
ret[i] = v0[i] ^ v1[i];
return ret;
}
#ifdef PIP_STD_IOSTREAM
//! \relatesalso PIByteArray \brief Output to std::ostream operator
inline std::ostream & operator<<(std::ostream & s, const PIByteArray & ba);

View File

@@ -11,13 +11,6 @@ const char * pageTitle = "<!DOCTYPE html>"
"</body>"
"</html>";
template<typename T>
PIString stringify(const T & v) {
PIString ret;
PICout::withExternalBuffer(&ret, 0, PICoutManipulators::AddSpaces) << v;
return ret;
}
int main(int argc, char * argv[]) {
PIHTTPServer server;
server.listen({"127.0.0.1:7777"});
@@ -30,9 +23,9 @@ int main(int argc, char * argv[]) {
server.registerUnhandled([](const PIHTTP::MessageConst & msg) -> PIHTTP::MessageMutable {
PIHTTP::MessageMutable ret;
piCout << "server rec:\n\tpath: %1\n\tmethod: %2\n\targs: %3\n\theaders: %4\n\tbody: %5\n"_a.arg(msg.path())
.arg((int)msg.method())
.arg(stringify(msg.arguments()))
.arg(PIStringList(msg.headers().map<PIString>([](PIString k, PIString v) { return k + " = " + v; })).join("\n\t\t"))
.arg(PIHTTP::methodName(msg.method()))
.arg(piStringify(msg.arguments()))
.arg(PIStringList(msg.headers().map<PIString>([](PIString k, PIString v) { return k + " = " + v; })).join("\n\t\t "))
.arg(PIString::fromUTF8(msg.body()));
ret.setCode(PIHTTP::Code::BadRequest);
ret.setBody(PIByteArray::fromAscii("hello client! 0123456789"));
@@ -40,14 +33,15 @@ int main(int argc, char * argv[]) {
});
PIHTTP::MessageMutable req;
req.setBody(PIByteArray::fromAscii("hello server!"));
req.setBody(PIByteArray::fromAscii("hello server!")).addArgument("a0", "val.0").addArgument("a~r1", "знач,1"_u8);
auto * c = PIHTTPClient::create("http://u:p@127.0.0.1:7777/api", PIHTTP::Method::Get, req);
c->onFinish([](PIHTTP::MessageConst msg) {
piCout << "client rec:\n\tcode: %5\n\tpath: %1\n\tmethod: %2\n\targs: %3\n\tbody: %4\n"_a.arg(msg.path())
.arg((int)msg.method())
.arg(stringify(msg.arguments()))
.arg(PIString::fromUTF8(msg.body()))
.arg((int)msg.code());
piCout << "client rec:\n\tpath: %1\n\tmethod: %2\n\targs: %3\n\theaders: %4\n\tbody: %5\n"_a.arg(msg.path())
.arg(PIHTTP::methodName(msg.method()))
.arg(piStringify(msg.arguments()))
.arg(
PIStringList(msg.headers().map<PIString>([](PIString k, PIString v) { return k + " = " + v; })).join("\n\t\t "))
.arg(PIString::fromUTF8(msg.body()));
})
->onError([c](PIHTTP::MessageConst r) {
piCout << "error" << (int)r.code();
@@ -59,9 +53,10 @@ int main(int argc, char * argv[]) {
})
->start();
// piMSleep(500);
kbd.enableExitCapture();
WAIT_FOR_EXIT
piMSleep(500);
// kbd.enableExitCapture();
// WAIT_FOR_EXIT
kbd.stopAndWait();
server.stop();
// c->abort();