Introduction
Introduction Statistics Contact Development Disclaimer Help
Initial commit. - pee - Pee a password manager;Pee - because you have to...
git clone git://vernunftzentrum.de/pee.git
Log
Files
Refs
LICENSE
---
commit dcd1351050e076fccb2b080bd90f51e6c0b0d0ff
Author: Christian Kellermann <[email protected]>
Date: Fri, 8 Jan 2016 08:51:59 +0100
Initial commit.
All functionality is working so far, see TODO file for open ends.
Diffstat:
LICENSE | 19 +++++++++++++++++++
blake2-impl.h | 137 +++++++++++++++++++++++++++++++
blake2.h | 150 +++++++++++++++++++++++++++++++
blake2s-ref.c | 394 +++++++++++++++++++++++++++++++
crypto-helper.scm | 35 +++++++++++++++++++++++++++++++
pee.scm | 379 +++++++++++++++++++++++++++++++
todo.org | 9 +++++++++
7 files changed, 1123 insertions(+), 0 deletions(-)
---
diff --git a/LICENSE b/LICENSE
@@ -0,0 +1,19 @@
+The blake2s Hash function has been licensed under a Creative Commons CC0 1.0 U…
+The tweetnacl code is in the public domain.
+The tweetnacl egg is BSD licensed.
+
+The rest of the pee code comes with a ISC license.
+
+Copyright (c) 2016 Christian Kellermann <[email protected]>
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/blake2-impl.h b/blake2-impl.h
@@ -0,0 +1,137 @@
+/*
+ BLAKE2 reference source code package - reference C implementations
+
+ Written in 2012 by Samuel Neves <[email protected]>
+
+ To the extent possible under law, the author(s) have dedicated all copyright
+ and related and neighboring rights to this software to the public domain
+ worldwide. This software is distributed without any warranty.
+
+ You should have received a copy of the CC0 Public Domain Dedication along w…
+ this software. If not, see <http://creativecommons.org/publicdomain/zero/1.…
+*/
+#pragma once
+#ifndef __BLAKE2_IMPL_H__
+#define __BLAKE2_IMPL_H__
+
+#include <stdint.h>
+#include <string.h>
+
+static 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;
+ uint32_t w = *p++;
+ w |= ( uint32_t )( *p++ ) << 8;
+ w |= ( uint32_t )( *p++ ) << 16;
+ w |= ( uint32_t )( *p++ ) << 24;
+ return w;
+#endif
+}
+
+static 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;
+ uint64_t w = *p++;
+ w |= ( uint64_t )( *p++ ) << 8;
+ w |= ( uint64_t )( *p++ ) << 16;
+ w |= ( uint64_t )( *p++ ) << 24;
+ w |= ( uint64_t )( *p++ ) << 32;
+ w |= ( uint64_t )( *p++ ) << 40;
+ w |= ( uint64_t )( *p++ ) << 48;
+ w |= ( uint64_t )( *p++ ) << 56;
+ return w;
+#endif
+}
+
+static 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++ = ( uint8_t )w; w >>= 8;
+ *p++ = ( uint8_t )w; w >>= 8;
+ *p++ = ( uint8_t )w; w >>= 8;
+ *p++ = ( uint8_t )w;
+#endif
+}
+
+static 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++ = ( uint8_t )w; w >>= 8;
+ *p++ = ( uint8_t )w; w >>= 8;
+ *p++ = ( uint8_t )w; w >>= 8;
+ *p++ = ( uint8_t )w; w >>= 8;
+ *p++ = ( uint8_t )w; w >>= 8;
+ *p++ = ( uint8_t )w; w >>= 8;
+ *p++ = ( uint8_t )w; w >>= 8;
+ *p++ = ( uint8_t )w;
+#endif
+}
+
+static inline uint64_t load48( const void *src )
+{
+ const uint8_t *p = ( const uint8_t * )src;
+ uint64_t w = *p++;
+ w |= ( uint64_t )( *p++ ) << 8;
+ w |= ( uint64_t )( *p++ ) << 16;
+ w |= ( uint64_t )( *p++ ) << 24;
+ w |= ( uint64_t )( *p++ ) << 32;
+ w |= ( uint64_t )( *p++ ) << 40;
+ return w;
+}
+
+static inline void store48( void *dst, uint64_t w )
+{
+ uint8_t *p = ( uint8_t * )dst;
+ *p++ = ( uint8_t )w; w >>= 8;
+ *p++ = ( uint8_t )w; w >>= 8;
+ *p++ = ( uint8_t )w; w >>= 8;
+ *p++ = ( uint8_t )w; w >>= 8;
+ *p++ = ( uint8_t )w; w >>= 8;
+ *p++ = ( uint8_t )w;
+}
+
+static inline uint32_t rotl32( const uint32_t w, const unsigned c )
+{
+ return ( w << c ) | ( w >> ( 32 - c ) );
+}
+
+static inline uint64_t rotl64( const uint64_t w, const unsigned c )
+{
+ return ( w << c ) | ( w >> ( 64 - c ) );
+}
+
+static inline uint32_t rotr32( const uint32_t w, const unsigned c )
+{
+ return ( w >> c ) | ( w << ( 32 - c ) );
+}
+
+static inline uint64_t rotr64( const uint64_t w, const unsigned c )
+{
+ return ( w >> c ) | ( w << ( 64 - c ) );
+}
+
+/* prevents compiler optimizing out memset() */
+static 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
+
diff --git a/blake2.h b/blake2.h
@@ -0,0 +1,150 @@
+/*
+ BLAKE2 reference source code package - reference C implementations
+
+ Written in 2012 by Samuel Neves <[email protected]>
+
+ To the extent possible under law, the author(s) have dedicated all copyright
+ and related and neighboring rights to this software to the public domain
+ worldwide. This software is distributed without any warranty.
+
+ You should have received a copy of the CC0 Public Domain Dedication along w…
+ this software. If not, see <http://creativecommons.org/publicdomain/zero/1.…
+*/
+#pragma once
+#ifndef __BLAKE2_H__
+#define __BLAKE2_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+#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
+ };
+
+#pragma pack(push, 1)
+ typedef 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
+ uint8_t node_offset[6];// 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
+ } blake2s_param;
+
+ typedef struct __blake2s_state
+ {
+ uint32_t h[8];
+ uint32_t t[2];
+ uint32_t f[2];
+ uint8_t buf[2 * BLAKE2S_BLOCKBYTES];
+ size_t buflen;
+ uint8_t last_node;
+ } blake2s_state;
+
+ typedef 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
+ uint64_t node_offset; // 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
+ } blake2b_param;
+
+ typedef struct __blake2b_state
+ {
+ uint64_t h[8];
+ uint64_t t[2];
+ uint64_t f[2];
+ uint8_t buf[2 * BLAKE2B_BLOCKBYTES];
+ size_t buflen;
+ 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;
+ } blake2sp_state;
+
+ typedef struct __blake2bp_state
+ {
+ blake2b_state S[4][1];
+ blake2b_state R[1];
+ uint8_t buf[4 * BLAKE2B_BLOCKBYTES];
+ size_t buflen;
+ } blake2bp_state;
+#pragma pack(pop)
+
+ // Streaming API
+ int blake2s_init( blake2s_state *S, const uint8_t outlen );
+ int blake2s_init_key( blake2s_state *S, const uint8_t outlen, const void *ke…
+ int blake2s_init_param( blake2s_state *S, const blake2s_param *P );
+ int blake2s_update( blake2s_state *S, const uint8_t *in, uint64_t inlen );
+ int blake2s_final( blake2s_state *S, uint8_t *out, uint8_t outlen );
+
+ int blake2b_init( blake2b_state *S, const uint8_t outlen );
+ int blake2b_init_key( blake2b_state *S, const uint8_t outlen, const void *ke…
+ int blake2b_init_param( blake2b_state *S, const blake2b_param *P );
+ int blake2b_update( blake2b_state *S, const uint8_t *in, uint64_t inlen );
+ int blake2b_final( blake2b_state *S, uint8_t *out, uint8_t outlen );
+
+ int blake2sp_init( blake2sp_state *S, const uint8_t outlen );
+ int blake2sp_init_key( blake2sp_state *S, const uint8_t outlen, const void *…
+ int blake2sp_update( blake2sp_state *S, const uint8_t *in, uint64_t inlen );
+ int blake2sp_final( blake2sp_state *S, uint8_t *out, uint8_t outlen );
+
+ int blake2bp_init( blake2bp_state *S, const uint8_t outlen );
+ int blake2bp_init_key( blake2bp_state *S, const uint8_t outlen, const void *…
+ int blake2bp_update( blake2bp_state *S, const uint8_t *in, uint64_t inlen );
+ int blake2bp_final( blake2bp_state *S, uint8_t *out, uint8_t outlen );
+
+ // Simple API
+ int blake2s( uint8_t *out, const void *in, const void *key, const uint8_t ou…
+ int blake2b( uint8_t *out, const void *in, const void *key, const uint8_t ou…
+
+ int blake2sp( uint8_t *out, const void *in, const void *key, const uint8_t o…
+ int blake2bp( uint8_t *out, const void *in, const void *key, const uint8_t o…
+
+ static inline int blake2( uint8_t *out, const void *in, const void *key, con…
+ {
+ return blake2b( out, in, key, outlen, inlen, keylen );
+ }
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
+
diff --git a/blake2s-ref.c b/blake2s-ref.c
@@ -0,0 +1,394 @@
+/*
+ BLAKE2 reference source code package - reference C implementations
+
+ Written in 2012 by Samuel Neves <[email protected]>
+
+ To the extent possible under law, the author(s) have dedicated all copyright
+ and related and neighboring rights to this software to the public domain
+ worldwide. This software is distributed without any warranty.
+
+ You should have received a copy of the CC0 Public Domain Dedication along w…
+ this software. If not, see <http://creativecommons.org/publicdomain/zero/1.…
+*/
+
+#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 inline int blake2s_set_lastnode( blake2s_state *S )
+{
+ S->f[1] = -1;
+ return 0;
+}
+
+static inline int blake2s_clear_lastnode( blake2s_state *S )
+{
+ S->f[1] = 0;
+ return 0;
+}
+
+/* Some helper functions, not necessarily useful */
+static inline int blake2s_set_lastblock( blake2s_state *S )
+{
+ if( S->last_node ) blake2s_set_lastnode( S );
+
+ S->f[0] = -1;
+ return 0;
+}
+
+static inline int blake2s_clear_lastblock( blake2s_state *S )
+{
+ if( S->last_node ) blake2s_clear_lastnode( S );
+
+ S->f[0] = 0;
+ return 0;
+}
+
+static inline int blake2s_increment_counter( blake2s_state *S, const uint32_t …
+{
+ S->t[0] += inc;
+ S->t[1] += ( S->t[0] < inc );
+ return 0;
+}
+
+// Parameter-related functions
+static inline int blake2s_param_set_digest_length( blake2s_param *P, const uin…
+{
+ P->digest_length = digest_length;
+ return 0;
+}
+
+static inline int blake2s_param_set_fanout( blake2s_param *P, const uint8_t fa…
+{
+ P->fanout = fanout;
+ return 0;
+}
+
+static inline int blake2s_param_set_max_depth( blake2s_param *P, const uint8_t…
+{
+ P->depth = depth;
+ return 0;
+}
+
+static inline int blake2s_param_set_leaf_length( blake2s_param *P, const uint3…
+{
+ store32( &P->leaf_length, leaf_length );
+ return 0;
+}
+
+static inline int blake2s_param_set_node_offset( blake2s_param *P, const uint6…
+{
+ store48( P->node_offset, node_offset );
+ return 0;
+}
+
+static inline int blake2s_param_set_node_depth( blake2s_param *P, const uint8_…
+{
+ P->node_depth = node_depth;
+ return 0;
+}
+
+static inline int blake2s_param_set_inner_length( blake2s_param *P, const uint…
+{
+ P->inner_length = inner_length;
+ return 0;
+}
+
+static inline int blake2s_param_set_salt( blake2s_param *P, const uint8_t salt…
+{
+ memcpy( P->salt, salt, BLAKE2S_SALTBYTES );
+ return 0;
+}
+
+static inline int blake2s_param_set_personal( blake2s_param *P, const uint8_t …
+{
+ memcpy( P->personal, personal, BLAKE2S_PERSONALBYTES );
+ return 0;
+}
+
+static inline int blake2s_init0( blake2s_state *S )
+{
+ memset( S, 0, sizeof( blake2s_state ) );
+
+ for( int i = 0; i < 8; ++i ) S->h[i] = blake2s_IV[i];
+
+ return 0;
+}
+
+/* init2 xors IV with input parameter block */
+int blake2s_init_param( blake2s_state *S, const blake2s_param *P )
+{
+ blake2s_init0( S );
+ const uint32_t *p = ( const uint32_t * )( P );
+
+ /* IV XOR ParamBlock */
+ for( size_t i = 0; i < 8; ++i )
+ S->h[i] ^= load32( &p[i] );
+
+ return 0;
+}
+
+
+// Sequential blake2s initialization
+int blake2s_init( blake2s_state *S, const uint8_t outlen )
+{
+ blake2s_param P[1];
+
+ /* Move interval verification here? */
+ if ( ( !outlen ) || ( outlen > BLAKE2S_OUTBYTES ) ) return -1;
+
+ P->digest_length = outlen;
+ P->key_length = 0;
+ P->fanout = 1;
+ P->depth = 1;
+ store32( &P->leaf_length, 0 );
+ store48( &P->node_offset, 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, const uint8_t outlen, const void *key,…
+{
+ blake2s_param P[1];
+
+ if ( ( !outlen ) || ( outlen > BLAKE2S_OUTBYTES ) ) return -1;
+
+ if ( !key || !keylen || keylen > BLAKE2S_KEYBYTES ) return -1;
+
+ P->digest_length = outlen;
+ P->key_length = keylen;
+ P->fanout = 1;
+ P->depth = 1;
+ store32( &P->leaf_length, 0 );
+ store48( &P->node_offset, 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 stac…
+ }
+ return 0;
+}
+
+static int blake2s_compress( blake2s_state *S, const uint8_t block[BLAKE2S_BLO…
+{
+ uint32_t m[16];
+ uint32_t v[16];
+
+ for( size_t i = 0; i < 16; ++i )
+ m[i] = load32( block + i * sizeof( m[i] ) );
+
+ for( size_t 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];
+#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)
+ ROUND( 0 );
+ ROUND( 1 );
+ ROUND( 2 );
+ ROUND( 3 );
+ ROUND( 4 );
+ ROUND( 5 );
+ ROUND( 6 );
+ ROUND( 7 );
+ ROUND( 8 );
+ ROUND( 9 );
+
+ for( size_t i = 0; i < 8; ++i )
+ S->h[i] = S->h[i] ^ v[i] ^ v[i + 8];
+
+#undef G
+#undef ROUND
+ return 0;
+}
+
+
+int blake2s_update( blake2s_state *S, const uint8_t *in, uint64_t inlen )
+{
+ while( inlen > 0 )
+ {
+ size_t left = S->buflen;
+ size_t fill = 2 * BLAKE2S_BLOCKBYTES - left;
+
+ if( inlen > fill )
+ {
+ memcpy( S->buf + left, in, fill ); // Fill buffer
+ S->buflen += fill;
+ blake2s_increment_counter( S, BLAKE2S_BLOCKBYTES );
+ blake2s_compress( S, S->buf ); // Compress
+ memcpy( S->buf, S->buf + BLAKE2S_BLOCKBYTES, BLAKE2S_BLOCKBYTES ); // Sh…
+ S->buflen -= BLAKE2S_BLOCKBYTES;
+ in += fill;
+ inlen -= fill;
+ }
+ else // inlen <= fill
+ {
+ memcpy( S->buf + left, in, inlen );
+ S->buflen += inlen; // Be lazy, do not compress
+ in += inlen;
+ inlen -= inlen;
+ }
+ }
+
+ return 0;
+}
+
+int blake2s_final( blake2s_state *S, uint8_t *out, uint8_t outlen )
+{
+ uint8_t buffer[BLAKE2S_OUTBYTES] = {0};
+
+ if( outlen > BLAKE2S_OUTBYTES )
+ return -1;
+
+ if( S->buflen > BLAKE2S_BLOCKBYTES )
+ {
+ blake2s_increment_counter( S, BLAKE2S_BLOCKBYTES );
+ blake2s_compress( S, S->buf );
+ S->buflen -= BLAKE2S_BLOCKBYTES;
+ memcpy( S->buf, S->buf + BLAKE2S_BLOCKBYTES, S->buflen );
+ }
+
+ blake2s_increment_counter( S, ( uint32_t )S->buflen );
+ blake2s_set_lastblock( S );
+ memset( S->buf + S->buflen, 0, 2 * BLAKE2S_BLOCKBYTES - S->buflen ); /* Padd…
+ blake2s_compress( S, S->buf );
+
+ for( int 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 );
+ return 0;
+}
+
+int blake2s( uint8_t *out, const void *in, const void *key, const uint8_t outl…
+{
+ 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 inl…
+{
+ return blake2s( out, in, NULL, BLAKE2S_OUTBYTES, inlen, 0 );
+}
+#endif
+
+#if defined(BLAKE2S_SELFTEST)
+#include <string.h>
+#include "blake2-kat.h"
+int main( int argc, char **argv )
+{
+ uint8_t key[BLAKE2S_KEYBYTES];
+ uint8_t buf[KAT_LENGTH];
+
+ for( size_t i = 0; i < BLAKE2S_KEYBYTES; ++i )
+ key[i] = ( uint8_t )i;
+
+ for( size_t i = 0; i < KAT_LENGTH; ++i )
+ buf[i] = ( uint8_t )i;
+
+ for( size_t i = 0; i < KAT_LENGTH; ++i )
+ {
+ uint8_t hash[BLAKE2S_OUTBYTES];
+ blake2s( hash, buf, key, BLAKE2S_OUTBYTES, i, BLAKE2S_KEYBYTES );
+
+ if( 0 != memcmp( hash, blake2s_keyed_kat[i], BLAKE2S_OUTBYTES ) )
+ {
+ puts( "error" );
+ return -1;
+ }
+ }
+
+ puts( "ok" );
+ return 0;
+}
+#endif
+
+
diff --git a/crypto-helper.scm b/crypto-helper.scm
@@ -0,0 +1,35 @@
+(module crypto-helper (arc4random hash-passphrase)
+ (import chicken scheme foreign)
+ (use blob-hexadecimal (srfi 4))
+ (foreign-declare "#include \"blake2.h\"")
+ (foreign-declare "#include \"blake2-impl.h\"")
+
+ (define-foreign-variable blake2s-outbytes integer "BLAKE2S_OUTBYTES")
+
+ (define blake2s
+ (foreign-lambda*
+ int
+ ((c-string passphrase)
+ ((scheme-pointer unsigned-char) out))
+ "
+ int res = 0;
+ explicit_bzero(out, BLAKE2S_OUTBYTES);
+ res = blake2s(out, passphrase, NULL, BLAKE2S_OUTBYTES, strlen(passp…
+ C_return(res);
+ "))
+
+ (define (hash-passphrase passphrase)
+ (let ((out (make-blob blake2s-outbytes)))
+ (if (not (zero? (blake2s passphrase out)))
+ (error "Unable to hash passphrase with blake2s")
+ out)))
+
+ (define (arc4random len)
+ (let ((buf (make-blob len)))
+ ((foreign-lambda
+ void
+ "arc4random_buf"
+ (scheme-pointer void)
+ size_t) buf len)
+ (blob->u8vector buf)))
+)
diff --git a/pee.scm b/pee.scm
@@ -0,0 +1,379 @@
+;; Pee - A password manager for the command line
+;;
+;; Copyright (c) 2016 Christian Kellermann <[email protected]>
+;;
+;; Permission to use, copy, modify, and distribute this software for any
+;; purpose with or without fee is hereby granted, provided that the above
+;; copyright notice and this permission notice appear in all copies.
+;;
+;; THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+;; WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+;; MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+;; ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+;; WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+;; ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+;; OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+(use (srfi 1 4) matchable posix tweetnacl utils crypto-helper getopt-long stty)
+
+(define-constant program-name "pee")
+(define-constant program-version "0.1")
+(define-constant program-description "A password manager for the command line.…
+
+(define-constant password-chars "abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRST…
+
+(define entropy-per-char
+ (inexact->exact (floor (* (/ (log (string-length password-chars)) (log 2)) 1…
+
+(define wanted-entropy (* 20 8))
+
+(define (generate-new-password wanted-entropy)
+ (define (new-indices len)
+ (let loop ((len len)
+ (idx '()))
+ (cond ((zero? len) idx)
+ (else
+ (let ((new (filter (lambda (n)
+ (< n (string-length password-chars)))
+ (u8vector->list (arc4random len)))))
+ (loop (- len (length new)) (append new idx)))))))
+ (list->string (map (lambda (i)
+ (string-ref password-chars i))
+ (new-indices (inexact->exact
+ (round (/ (* 100 wanted-entropy) entropy-pe…
+
+(define (prompt-for msg #!optional default)
+ (if default (printf "~a [~a]: " msg default)
+ (printf "~a: " msg))
+ (let ((l (read-line)))
+ (if (and default (equal? "" l))
+ default
+ l)))
+
+(define (ask-for-choice msg . options)
+ (with-stty
+ '(not echo icanon opost)
+ (lambda ()
+ (let loop ()
+ (printf "~a [~a]: " msg (apply string-append options))
+ (let ((answer (string (read-char))))
+ (cond ((member answer options) =>
+ (lambda (c)
+ (printf "\r")
+ (car c)))
+ (else (printf "\r") (loop))))))))
+
+(define (new-password)
+ (define (ask-for-manual-password)
+ (with-stty
+ '(not echo)
+ (lambda ()
+ (printf "Enter new password: ")
+ (read-line)
+ (print "\r"))))
+ (let manual-loop ()
+ (if (equal? "y"
+ (ask-for-choice "Invent your own password?" "y" "n"))
+ (let ((p1 (ask-for-manual-password))
+ (p2 (ask-for-manual-password)))
+ (unless (equal? p1 p2) (print "Passwords do not match.") (manual-loo…
+ (let password-loop ((e wanted-entropy))
+ (let ((p (generate-new-password e))
+ (entropy-delta (cond ((< e 64) 8)
+ ((< e 128) 16)
+ (else 32))))
+ (printf "Length ~a chars, entropy ~a bits~%" (string-length p) (qu…
+ (print p)
+ (let ((choice (ask-for-choice "Use this password?" "y" "n" "+" "-"…
+ (cond ((member choice '(" " "n")) (password-loop e))
+ ((equal? choice "+") (password-loop (+ e entropy-delta)))
+ ((equal? choice "-") (password-loop (max 32 (- e entropy-d…
+ ((equal? choice "?")
+ (printf "y - accept password~%+ - increase password lengt…
+ (password-loop e))
+ (else p))))))))
+
+(define (get-hashed-passphrase)
+ (with-stty
+ '(not echo)
+ (lambda ()
+ (display "Enter passphrase: " (current-error-port))
+ (let ((l (read-line)))
+ (newline (current-error-port))
+ (hash-passphrase l)))))
+
+(define (enc/dec-file content passphrase op)
+ (let ((sbox (op passphrase))
+ (nonce (make-u8vector symmetric-box-noncebytes 0)))
+ (sbox content nonce)))
+
+(define (decrypt-file file passphrase)
+ (let ((content (with-input-from-file file read-all)))
+ (enc/dec-file content passphrase symmetric-unbox)))
+
+(define (encrypt-file file content passphrase)
+ (with-output-to-file file
+ (lambda () (display (enc/dec-file content passphrase symmetric-box)))))
+
+(define (db-keys alist) (map car alist))
+
+(define (search-entry db entry)
+ (let* ((regex (string->irregex (string-append ".*" entry ".*") 'i 'utf8))
+ (result
+ (find (lambda (k) (irregex-match regex k))
+ (db-keys db))))
+ (and result
+ (not (null? result))
+ (cons result (alist-ref result db equal?)))))
+
+(define (get-result db entry op)
+ (let ((entry (search-entry db entry)))
+ (and entry (> (length entry) 1) (op entry))))
+
+(define (get-user db entry)
+ (get-result db entry second))
+
+(define (get-password db entry)
+ (get-result db entry third))
+
+(define (get-comment db entry)
+ (get-result db entry fourth))
+
+(define (update-db db key #!key user password comment)
+ (let ((entry (or (alist-ref key db equal?) (make-list 3 ""))))
+ (alist-update key
+ (match-let (((u p c) entry))
+ (list
+ (or user u)
+ (or password p)
+ (or comment c)))
+ db
+ equal?)))
+
+(define (check-access f)
+ (and (file-exists? f)
+ (file-read-access? f)
+ (file-write-access? f)))
+
+(define options
+ `((init
+ "Initialise password store"
+ (required #f)
+ (value #f)
+ (single-char #\i))
+ (add
+ "Add a new entry to the password store"
+ (required #f)
+ (value (required ACCOUNT)
+ (predicate ,string?))
+ (single-char #\a))
+ (password
+ "Get the password for a given entry"
+ (required #f)
+ (value (required ACCOUNT)
+ (predicate ,string?))
+ (single-char #\p))
+ (update
+ "Change an existing entry in the database"
+ (required #f)
+ (value (required ACCOUNT)
+ (predicate ,string?))
+ (single-char #\u))
+ (delete
+ "Drop an entry from the database"
+ (required #f)
+ (value (required ACCOUNT)
+ (predicate ,string?))
+ (single-char #\d))
+ (list
+ "Shows all info for an entry. Does not show the password."
+ (required #f)
+ (value (required ACCOUNT)
+ (predicate ,string?))
+ (single-char #\l))
+ (change-passphrase
+ "Reencrypts the store with a new passphrase. Use it regularily."
+ (required #f)
+ (value #f)
+ (single-char #\c))
+ (database-file
+ "Use FILE as the database"
+ (required #f)
+ (single-char #\f)
+ (value (required FILE)
+ (predicate ,check-access)))
+ (export
+ "Prints the database as an association list (s-expression) on stdout"
+ (required #f)
+ (value #f))
+ (import
+ "Reads an association list from FILE, the inverse of export."
+ (required #f)
+ (value (required FILE)
+ (predicate ,check-access)))
+ (version
+ "Print program version"
+ (required #f)
+ (single-char #\v)
+ (value #f))
+ (help
+ "Prints this help"
+ (required #f)
+ (single-char #\h)
+ (value #f))))
+
+(define (banner)
+ (printf "~a Version ~a -- ~a~%" program-name program-version program-descrip…
+
+(define (print-without-password e)
+ (printf "Account: ~a\tUser: ~a\tComment: ~a~%"
+ (first e)
+ (second e)
+ (fourth e)))
+
+(define (do-add db-name db p e)
+ (when (alist-ref e db equal?)
+ (print "Error: An entry for '" e "' already exists.")
+ (exit 1))
+ (let ((user (prompt-for "Username"))
+ (password (new-password))
+ (comment (prompt-for "Comment")))
+ (unless (encrypt-file db-name
+ (with-output-to-string (lambda ()
+ (pp (cons (list e user pass…
+ p)
+ (print "Error while encrypting password store")
+ (exit 1))
+ (print "Entry for " e " added.")))
+
+(define (do-update db-name db p account)
+ (cond ((alist-ref account db equal?) =>
+ (lambda (e)
+ (let ((user (prompt-for "User" (first e)))
+ (comment (prompt-for "Comment" (third e)))
+ (password (if (equal? "y"
+ (ask-for-choice "Change password?" "y" …
+ (new-password)
+ (second e))))
+ (unless (encrypt-file db-name
+ (with-output-to-string
+ (lambda ()
+ (pp (alist-update account (list user pa…
+ p)
+ (print "Error: Encryption failed.")
+ (exit 1))
+ (print "Entry '" account "' has been updated."))))
+ (else (print "Error> Entry for '" account "' not found.")
+ (exit 1))))
+
+(define (do-delete db-name db p account)
+ (cond ((alist-ref account db equal?) =>
+ (lambda (e)
+ (print-without-password (cons account e))
+ (if (equal? "y" (ask-for-choice "Really delete account?" "y" "n"))
+ (if (encrypt-file db-name (with-output-to-string (lambda () (pp…
+ (print "Entry '" (car e) "' deleted.")
+ (begin
+ (print "Error: Encryption failed")
+ (exit 1)))
+ (print "Nothing done."))))
+ (else (print "Error: Entry for '" account "' not found")
+ (exit 1))))
+
+(define (do-list db account)
+ (let* ((regex (string->irregex (string-append ".*" account ".*") 'i 'utf8))
+ (accounts
+ (filter (lambda (k)
+ (irregex-match regex k))
+ (db-keys db))))
+ (when (null? accounts)
+ (print "Error: No entry for " account " found.")
+ (exit 1))
+ (for-each
+ (lambda (e)
+ (print-without-password e))
+ (map (lambda (account)
+ (get-result db account identity))
+ accounts))))
+
+(define (do-password db e)
+ (let ((p (get-password db e)))
+ (if p (print p)
+ (begin
+ (print "Error: password for " e " not found.")
+ (exit 1)))))
+
+(define (do-init db-name content)
+ (print "I will ask you twice for the passphrase to encrypt the password stor…
+ (let ((passphrase1 (get-hashed-passphrase))
+ (passphrase2 (get-hashed-passphrase)))
+ (unless (equal? passphrase1 passphrase2)
+ (print "Error: Passphrases do not match.")
+ (print passphrase1 passphrase2)
+ (exit 1))
+ (cond ((encrypt-file db-name (with-output-to-string (lambda () (pp content…
+ (print "Password store " db-name " initialised.")
+ (exit 0))
+ (else
+ (print "Could not encrypt password store.")
+ (exit 1)))))
+
+(define (do-change-passphrase db-name db old-passphrase)
+ (print "I will ask you twice for the new passphrase.")
+ (let ((passphrase1 (get-hashed-passphrase))
+ (passphrase2 (get-hashed-passphrase)))
+ (cond ((not (equal? passphrase1 passphrase2))
+ (print "Error: Passphrases do not match.")
+ (exit 1))
+ ((equal? passphrase1 old-passphrase)
+ (print "Error: Passphrase is the same as old passphrase")
+ (exit 1))
+ ((encrypt-file db-name (with-output-to-string (lambda () (pp db)))…
+ (print "Password store " db-name " reencrypted."))
+ (else
+ (print "Could not re-encrypt password store.")
+ (exit 1)))))
+
+(define (main args)
+ (let* ((opts
+ (condition-case
+ (getopt-long args options)
+ (e (exn)
+ (print "Error: "
+ ((condition-property-accessor 'exn 'arguments) e) " "
+ ((condition-property-accessor 'exn 'message) e))
+ (banner)
+ (print (usage options))
+ (exit 1))))
+ (db-name (or (alist-ref 'database-file opts)
+ (make-pathname (get-environment-variable "HOME") ".passd…
+ (init (alist-ref 'init opts)))
+
+ (unless (null? (alist-ref '@ opts equal?))
+ (fprintf (current-error-port) "Warning: superfluous option given: …
+ (fprintf (current-error-port) "Using database file ~a~%" db-name)
+ (unless (or init (check-access db-name))
+ (print "Error database " db-name " does not exist or has wrong per…
+ (cond
+ ((alist-ref 'help opts) (banner) (print (usage options)))
+ ((alist-ref 'version opts) (banner))
+ ((alist-ref 'import opts) => (lambda (f)
+ (do-init db-name (with-input-from-file f r…
+
+ (init (do-init db-name '()))
+ (else
+ (let* ((passphrase (get-hashed-passphrase))
+ (db (or (with-input-from-string (or (decrypt-file db-name passphr…
+ (begin (print "Error while decrypting " db-name ", wrong …
+ (cond
+ ((alist-ref 'change-passphrase opts)
+ (do-change-passphrase db-name db passphrase))
+ ((alist-ref 'add opts) => (lambda (e) (do-add db-name db passphrase e…
+ ((alist-ref 'list opts) => (lambda (e) (do-list db e)))
+ ((alist-ref 'export opts) (pp db))
+ ((alist-ref 'delete opts) => (lambda (e) (do-delete db-name db passph…
+ ((alist-ref 'update opts) => (lambda (e) (do-update db-name db passph…
+ ((alist-ref 'password opts) => (lambda (e) (do-password db e)))
+ (else (banner) (print "Error: Don't know what to do") (print (usage o…
+ (exit 0)))
+
diff --git a/todo.org b/todo.org
@@ -0,0 +1,9 @@
+* TODOs
+** Do we need to feed arc4random into tweetnacl for better randomness?
+** initialise-db should not overwrite the file so easily
+** Add a version counter to the file, so we can make assumptions about the fil…
+** Refactor the exit code
+** Refactor the encryption code
+** Make password prompts not echo the password on the terminal
+** Make ask-for-choice react on a single keystroke
+** Add a last modified date to entries, this should make it easier when mergin…
You are viewing proxied material from vernunftzentrum.de. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.