ekeyd-1.1.5/0002775000175000017500000000000011672145156010445 5ustar pmpmekeyd-1.1.5/AUTHORS0000664000175000017500000000110311435473174011507 0ustar pmpmEntropy Key - List of authors ============================= If you have any questions about the Entropy Key or this software then please contact ekey@simtec.co.uk directly. The Entropy Key host software was written by: - Daniel Silverstone - Vincent Sanders - Rob Kendrick This software contains some code written by David Manura. Patches to support MirBSD and to better support OpenBSD provided by Thorsten Glaser. Significant patches to improve performance provided by Nicholas Alcock The implementation of Skein used in this software was written by Doug Whiting. ekeyd-1.1.5/munin/0002775000175000017500000000000011672145152011567 5ustar pmpmekeyd-1.1.5/munin/plugin-conf.d_ekeyd0000664000175000017500000000007611250010772015326 0ustar pmpm[ekeyd_stat_*] user root env.controlsocket /var/run/ekeyd.sockekeyd-1.1.5/munin/ekeyd_stat_0000775000175000017500000001365211634112443014010 0ustar pmpm#!/usr/bin/perl -w # # Entropy Key statistic reporting plugin for munin # # use by soft linking the script to a ekey statistic # for example ln -s /usr/share/munin/ekeyd_stat_ ekeyd_stat_KeyTemperatureC # will give a graph of each entropy keys temperature in Celsius # # for example ln -s /usr/share/munin/ekeyd_stat_ ekeyd_stat_total_EntropyRate # will give a graph of the total entropy rate from all keys in bits per second # # The plugin.conf.d/munin-node must have a stanza [ekeyd_*] with user root in # it as the plugin requires root access to aquire the statistics # # Copyright 2009 Simtec Electronics # # For licence terms refer to the COPYING file. # Magic markers for munin #%# family=auto #%# capabilities=autoconf suggest use strict; use Socket; use IO::Handle; my $control_sock = exists $ENV{controlsocket} ? $ENV{controlsocket} : '/var/run/ekeyd.sock'; # mappings to make output prettier my %titles = ("KeyTemperatureC", "Temperature" ,"KeyTemperatureF", "Temperature", "KeyTemperatureK" , "Temperature" , "TotalEntropy", "Entropy Rate", "KeyVoltage", "Supply Voltage", "FipsFrameRate", "Fips Frame Rate", "EntropyRate", "Entropy Rate"); my %graph_axis = ( "KeyTemperatureC", "Celsius", "KeyTemperatureF", "Fahrenheit", "KeyTemperatureK", "Kelvin" , "EntropyRate", "Bits per second" , "TotalEntropy", "Bytes per second" , "KeyVoltage", "Volts", "ConnectionTime", "Seconds", "FipsFrameRate", "Frames per second"); my %graph_type = ( "TotalEntropy" , "DERIVE", "BytesRead" , "COUNTER", "BytesWritten" , "COUNTER", "ConnectionPackets" , "COUNTER" ); my %graph_min = ( "TotalEntropy" , 0 ); sub ekeyd_connect { my ($rendezvous) = @_; my $line; my $sock; socket($sock, PF_UNIX, SOCK_STREAM, 0) || die "socket: $!"; connect($sock, sockaddr_un($rendezvous)) || die "connect: $!"; $line = <$sock>; if ((!defined($line)) || ($line ne "PROTOCOL EKEYD/1\n")) { die "Unrecognised EKEYD " . $line; } return $sock; } # issues a command to the ekeyd and retrieves the results sub ekeyd_command { my ($sock, $command, @params) = @_; my @lines; my $line; my $pnum = scalar @params; if ($pnum > 0) { my $pcnt = 0; $command .= "("; while ($pcnt < $pnum) { $command = $command . "\"" . $params[$pcnt] . "\""; $pcnt++; if ($pcnt == $pnum) { $command .= ")"; } else { $command .= ","; } } } print $sock $command . "\n"; $sock->flush; push @lines, $line while ((defined($line = <$sock>)) and $line ne "OK\n" and $line !~ "^ERROR.*"); chomp @lines; return @lines; } # discover if plugin can actually be used on this system if ( defined $ARGV[0] and $ARGV[0] eq "autoconf" ) { if ($control_sock and -S $control_sock) { print "yes\n"; exit 0; } else { print "no (Control socket $control_sock not found)\n"; exit 1; } } # suggest appropriate default links if ( defined $ARGV[0] and $ARGV[0] eq "suggest" ) { print "total_TotalEntropy\n"; print "KeyTemperatureC\n"; exit 0; } # aquire the name of the statistic to monitor. $0 =~ /ekeyd_stat_total_(.+)*$/; my $statistic = $1; my $total_flag = 1; if (!defined($statistic)) { $0 =~ /ekeyd_stat_(.+)*$/; $statistic = $1; $total_flag = 0; if (!defined($statistic)) { die "A statistic must be provided"; } } # connect to the ekeyd command socket my $SOCKET = ekeyd_connect($control_sock); # find all the entropy keys attached my @result = ekeyd_command($SOCKET, "ListEntropyKeys"); # remove header line shift @result; if ( defined $ARGV[0] and $ARGV[0] eq "config" ) { # work out graph title my $title; if (defined $titles{$statistic}) { $title = $titles{$statistic}; } else { $title = $statistic; } if ($total_flag == 1) { if (scalar(@result) < 2) { print "graph_title Entropy Key " . $title . "\n"; } else { print "graph_title Entropy Key Combined " . $title . "\n"; } } else { print "graph_title Entropy Key " . $title . "\n"; } # label the axis as apropriate if (defined $graph_axis{$statistic}) { print "graph_vlabel " . $graph_axis{$statistic} . "\n"; } print "graph_category sensors\n"; if ($total_flag == 1) { if (scalar(@result) < 2) { print "totstat.label $title\n"; } else { print "totstat.label Combined $title for " . scalar(@result) . " Entropy Keys\n"; } # set the graph type if (defined $graph_type{$statistic}) { print "totstat.type " . $graph_type{$statistic} . "\n"; } else { print "totstat.type GAUGE\n"; } #set the graph minimum if (defined $graph_min{$statistic}) { print "totstat.min " . $graph_min{$statistic} . "\n"; } } else { # details for each key foreach my $keyline (@result) { my @elmnt = split(/\t/, $keyline); my $name = $elmnt[5]; $name =~ s,/,_,g; print "stats" . $name . ".label " . $elmnt[5] . "\n"; # set the graph type if (defined $graph_type{$statistic}) { print "stats" . $name . ".type " . $graph_type{$statistic} . "\n"; } else { print "stats" . $name . ".type GAUGE\n"; } #set the graph minimum if (defined $graph_min{$statistic}) { print "stats". $name . ".min " . $graph_min{$statistic} . "\n"; } } } } else { my $total = 0; foreach my $keyline (@result) { # split up the result line my @elmnt = split(/\t/, $keyline); my $name = $elmnt[5]; $name =~ s,/,_,g; # get the status of the entropy key my @stat_res = ekeyd_command($SOCKET, "StatEntropyKey", $elmnt[5]); my $tmp; my %key_stats; foreach $tmp (@stat_res) { my @keyval = split(/\t/, $tmp); @keyval = split(/=/, $keyval[1]); $key_stats{$keyval[0]} = $keyval[1]; } $total += $key_stats{$statistic}; if ($total_flag == 0) { print "stats" . $name . ".value " . $key_stats{$statistic} . "\n"; } } if ($total_flag == 1) { if (scalar(@result) < 1) { $total = "U"; } print "totstat.value " . $total . "\n"; } } close $SOCKET; exit 0; ekeyd-1.1.5/ChangeLog0000664000175000017500000000771511672137034012223 0ustar pmpmSimtec Electronics Entropy Key -- Host Software ChangeLog --------------------------------------------------------- This document summarises the changes between public releases of the Entropy Key host software. v1.1.5 * Fix use after free. * Make the invocation of udev reload robust when udev is not installed (Debian bug #640597) * Debian bug #598317: Fix escaping of slashes in the munin script. * Debian bug #576387: Define a default retry interval. * Ubuntu bug #625446: Fix manpages of ekeyd-rekey and ekeyd-setkey, and add a warning to ekeyd-setkey's usage text. * Remove confusing Lua long-comments from ekeyd.conf. v1.1.4 * Improve ekey-rekey command line handling so master key can be entered interactively. * Improve ekey-rekey command locating suitable USB devices automatically. * Improve host tools Makefile to install egd-linux if built * Make EGD client cope with read timeouts v1.1.3 * Improve handling of failed rekeying. Will now attempt to re-establish a keyed session every 50 recived packets instead of leaving the connection "Long term key bad" * Removed some debug to improve CPU consumption. * PEM Decode speedup, courtesy of nix@esperi.org.uk * EGD Entropy dispatch speedup, courtesy of nix@esperi.org.uk * Key badness rework, courtesy of nix@esperi.org.uk * EGD-Linux tool resilient in the face of EINTR of poll() v1.1.2 * Various improvements in internal buffer management. * Improve serial number handling in ekey-rekey. * Support hostnames in egd-linux. - This patch provided by Tollef Fog Heen of Collabora. * Keyring writing in ekey-setkey is now more careful with its permissions. Concept courtesy of Kees Cook of Debian * Improve serial number handling in munin script. - This patch provided by Wouter Verhelst of Debian * Improve the TotalEntropy munin graph by setting a minimum for the Y axis. This corrects issues in the graph when the daemon restarts. v1.1.1 Fix bug where ekeyd would sit and spin if ekeydctl shutdown was used to stop the daemon. Improve logging and retry behaviour for ekeyd-egd-linux. Add a --device option to ekey-rekey and make it remove any spaces in the master key to make input more tolerant of users copying the spaces from the master key card. Update the state machine to better cope with unexpected buffering of the packet stream causing long-term-key-bad events where they were not correct. Lots of bits to support MirBSD thanks to Thorsten Glaser. Munin support updated and defaults altered to be of more use to normal people. v1.1.0 Improve the control over ekeyd-egd-linux connection retrying. Fix a memory leak in the EGD server implementation. Various exit-path cleanups, courtesy of Eric Sesterhenn. v1.0.7 Support the rekeying of Entropy Key devices whose serial numbers encode to contain a slash symbol. v1.0.6 Append entropy when writing to a file on disk. Hold off on issuing rekey nonces a little to produce more reliable rekeying behaviour during high load scenarios. Correct a bug in the ulusbd which caused "Vanished?" messages which were spurious as the devices were still connected. v1.0.5 Correct a logic hiccough in the no-pidfile path out of the daemonise function used by the daemons. Add some syslog() to the ulusbd to better diagnose issues related to it. v1.0.4 Munin scripts, better handling of poll() related errors in main daemon to allow for debugging via strace. Pointless writes in the EGD layer removed to reduce CPU consumption when no entropy is available but there are clients requesting it. An attempt at buildability on GNU/kFreeBSD. v1.0.3 Manual page updates, AUTHORS file, ekey-setkey now retries more effectively than before. v1.0.2 Additional copyright and authoring information along with clearer attribution for non-Simtec source in the software. v1.0.1 Corrected an issue related to multiple Entropy Key devices attached to the same ekeyd instance. v1.0 First public release of the Entropy Key software. ekeyd-1.1.5/THANKS0000664000175000017500000000127211556361136011357 0ustar pmpmSimtec Electronics, Entropy Key ------------------------------- In producing the Entropy Key device, firmware and host-side software, various people have helped by beta-testing hardware and software, or by providing invaluable assistance in getting the host software working on any given operating system. Simtec Electronics would therefore like to thank the following people for their aid. Bdale Garbee (Beta testing and stirring early interest) Elizabeth Garbee (Logo design) Jonathan Gray (OpenBSD assistance, OpenBSD ports updates) Lesley Mitchell (RPM packaging work) M Joonas Pihlaja (OpenBSD assistance) Daniel Stone (OpenBSD assistance) Nicholas Alcock (Lots optimisations and tidying) ekeyd-1.1.5/release.sh0000775000175000017500000000205011613272361012411 0ustar pmpm#!/bin/sh # Simtec entropy key release tar builder # usage: release.sh set -e # Determine current location LOC=$(svn info|grep URL|cut -d\ -f2-) if [ "${1}x" = "x" ]; then echo "Must supply a version number" exit 1 fi VERSION=${1} if [ -f ekeyd-${VERSION}.tar.gz ]; then exit 0 fi # if SVN credentials are provided to us, use them if [ "x${SVN_USER}" != "x" ]; then SVN_OPTS="--non-interactive --no-auth-cache --username ${SVN_USER} --password ${SVN_PASS}" else SVN_OPTS="" fi svn export ${SVN_OPTS} ${LOC} ekeyd-${VERSION} rm -fr ekeyd-${VERSION}/doc/*.pdf rm -fr ekeyd-${VERSION}/doc/*.txt rm -fr ekeyd-${VERSION}/doc/*.dot rm -fr ekeyd-${VERSION}/doc/*.svg rm -fr ekeyd-${VERSION}/device/ekey.* rm -fr ekeyd-${VERSION}/device/firmware rm -fr ekeyd-${VERSION}/tools rm -fr ekeyd-${VERSION}/debian rm -fr ekeyd-${VERSION}/rpm rm -fr ekeyd-${VERSION}/artwork rm -fr ekeyd-${VERSION}/bringup rm -fr ekeyd-${VERSION}/iso tar cfz ekeyd-${VERSION}.tar.gz ekeyd-${VERSION} rm -fr ekeyd-${VERSION} tar tfz ekeyd-${VERSION}.tar.gz ekeyd-1.1.5/device/0002775000175000017500000000000011672145156011704 5ustar pmpmekeyd-1.1.5/device/skeinwrap.c0000664000175000017500000000142411230660620014036 0ustar pmpm/* skeinwrap.c * * Wrappers for standard skein operations for the eKey * * Copyright 2009 Simtec Electronics * * For licence terms refer to the COPYING file. */ #include "skeinwrap.h" static unsigned char keybuf[44]; /* 12 bytes serial, 32 bytes secret */ void PrepareSkein(EKeySkein *skein, const unsigned char *serial, const unsigned char *secret, const char *personalisation) { int i; for (i = 0; i < 12; ++i) keybuf[i] = serial[i]; for (i = 0; i < 32; ++i) keybuf[i + 12] = secret[i]; Skein_256_InitExt(skein, 256, SKEIN_CFG_TREE_INFO_SEQUENTIAL, keybuf, 44); Skein_Start_New_Type(skein, PERS); Skein_256_Update(skein, (unsigned char *)personalisation, 96); Skein_Start_New_Type(skein, MSG); } ekeyd-1.1.5/device/skein/0002775000175000017500000000000011672145155013014 5ustar pmpmekeyd-1.1.5/device/skein/skein.h0000664000175000017500000003770011217665420014300 0ustar pmpm#ifndef _SKEIN_H_ #define _SKEIN_H_ 1 /************************************************************************** ** ** Interface declarations and internal definitions for Skein hashing. ** ** Source code author: Doug Whiting, 2008. ** ** This algorithm and source code is released to the public domain. ** *************************************************************************** ** ** The following compile-time switches may be defined to control some ** tradeoffs between speed, code size, error checking, and security. ** ** The "default" note explains what happens when the switch is not defined. ** ** SKEIN_DEBUG -- make callouts from inside Skein code ** to examine/display intermediate values. ** [default: no callouts (no overhead)] ** ** SKEIN_ERR_CHECK -- how error checking is handled inside Skein ** code. If not defined, most error checking ** is disabled (for performance). Otherwise, ** the switch value is interpreted as: ** 0: use assert() to flag errors ** 1: return SKEIN_FAIL to flag errors ** ***************************************************************************/ #include /* get size_t definition */ #include "skein_port.h" /* get platform-specific definitions */ enum { SKEIN_SUCCESS = 0, /* return codes from Skein calls */ SKEIN_FAIL = 1, SKEIN_BAD_HASHLEN = 2 }; #define SKEIN_MODIFIER_WORDS ( 2) /* number of modifier (tweak) words */ #define SKEIN_256_STATE_WORDS ( 4) #define SKEIN_512_STATE_WORDS ( 8) #define SKEIN1024_STATE_WORDS (16) #define SKEIN_MAX_STATE_WORDS (16) #define SKEIN_256_STATE_BYTES ( 8*SKEIN_256_STATE_WORDS) #define SKEIN_512_STATE_BYTES ( 8*SKEIN_512_STATE_WORDS) #define SKEIN1024_STATE_BYTES ( 8*SKEIN1024_STATE_WORDS) #define SKEIN_256_STATE_BITS (64*SKEIN_256_STATE_WORDS) #define SKEIN_512_STATE_BITS (64*SKEIN_512_STATE_WORDS) #define SKEIN1024_STATE_BITS (64*SKEIN1024_STATE_WORDS) #define SKEIN_256_BLOCK_BYTES ( 8*SKEIN_256_STATE_WORDS) #define SKEIN_512_BLOCK_BYTES ( 8*SKEIN_512_STATE_WORDS) #define SKEIN1024_BLOCK_BYTES ( 8*SKEIN1024_STATE_WORDS) typedef struct { size_t hashBitLen; /* size of hash result, in bits */ size_t bCnt; /* current byte count in buffer b[] */ u64b_t T[SKEIN_MODIFIER_WORDS]; /* tweak words: T[0]=byte cnt, T[1]=flags */ } Skein_Ctxt_Hdr_t; typedef struct /* 256-bit Skein hash context structure */ { Skein_Ctxt_Hdr_t h; /* common header context variables */ u64b_t X[SKEIN_256_STATE_WORDS]; /* chaining variables */ u08b_t b[SKEIN_256_BLOCK_BYTES]; /* partial block buffer (8-byte aligned) */ } Skein_256_Ctxt_t; typedef struct /* 512-bit Skein hash context structure */ { Skein_Ctxt_Hdr_t h; /* common header context variables */ u64b_t X[SKEIN_512_STATE_WORDS]; /* chaining variables */ u08b_t b[SKEIN_512_BLOCK_BYTES]; /* partial block buffer (8-byte aligned) */ } Skein_512_Ctxt_t; typedef struct /* 1024-bit Skein hash context structure */ { Skein_Ctxt_Hdr_t h; /* common header context variables */ u64b_t X[SKEIN1024_STATE_WORDS]; /* chaining variables */ u08b_t b[SKEIN1024_BLOCK_BYTES]; /* partial block buffer (8-byte aligned) */ } Skein1024_Ctxt_t; /* Skein APIs for (incremental) "straight hashing" */ int Skein_256_Init (Skein_256_Ctxt_t *ctx, size_t hashBitLen); int Skein_512_Init (Skein_512_Ctxt_t *ctx, size_t hashBitLen); int Skein1024_Init (Skein1024_Ctxt_t *ctx, size_t hashBitLen); int Skein_256_Update(Skein_256_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt); int Skein_512_Update(Skein_512_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt); int Skein1024_Update(Skein1024_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt); int Skein_256_Final (Skein_256_Ctxt_t *ctx, u08b_t * hashVal); int Skein_512_Final (Skein_512_Ctxt_t *ctx, u08b_t * hashVal); int Skein1024_Final (Skein1024_Ctxt_t *ctx, u08b_t * hashVal); /* ** Skein APIs for "extended" initialization: MAC keys, tree hashing. ** After an InitExt() call, just use Update/Final calls as with Init(). ** ** Notes: Same parameters as _Init() calls, plus treeInfo/key/keyBytes. ** When keyBytes == 0 and treeInfo == SKEIN_SEQUENTIAL, ** the results of InitExt() are identical to calling Init(). ** The function Init() may be called once to "precompute" the IV for ** a given hashBitLen value, then by saving a copy of the context ** the IV computation may be avoided in later calls. ** Similarly, the function InitExt() may be called once per MAC key ** to precompute the MAC IV, then a copy of the context saved and ** reused for each new MAC computation. **/ int Skein_256_InitExt(Skein_256_Ctxt_t *ctx, size_t hashBitLen, u64b_t treeInfo, const u08b_t *key, size_t keyBytes); int Skein_512_InitExt(Skein_512_Ctxt_t *ctx, size_t hashBitLen, u64b_t treeInfo, const u08b_t *key, size_t keyBytes); int Skein1024_InitExt(Skein1024_Ctxt_t *ctx, size_t hashBitLen, u64b_t treeInfo, const u08b_t *key, size_t keyBytes); /* ** Skein APIs for MAC and tree hash: ** Final_Pad: pad, do final block, but no OUTPUT type ** Output: do just the output stage */ int Skein_256_Final_Pad(Skein_256_Ctxt_t *ctx, u08b_t * hashVal); int Skein_512_Final_Pad(Skein_512_Ctxt_t *ctx, u08b_t * hashVal); int Skein1024_Final_Pad(Skein1024_Ctxt_t *ctx, u08b_t * hashVal); #ifndef SKEIN_TREE_HASH #define SKEIN_TREE_HASH (1) #endif #if SKEIN_TREE_HASH int Skein_256_Output (Skein_256_Ctxt_t *ctx, u08b_t * hashVal); int Skein_512_Output (Skein_512_Ctxt_t *ctx, u08b_t * hashVal); int Skein1024_Output (Skein1024_Ctxt_t *ctx, u08b_t * hashVal); #endif /***************************************************************** ** "Internal" Skein definitions ** -- not needed for sequential hashing API, but will be ** helpful for other uses of Skein (e.g., tree hash mode). ** -- included here so that they can be shared between ** reference and optimized code. ******************************************************************/ /* tweak word T[1]: bit field starting positions */ #define SKEIN_T1_BIT(BIT) ((BIT) - 64) /* offset 64 because it's the second word */ #define SKEIN_T1_POS_TREE_LVL SKEIN_T1_BIT(112) /* bits 112..118: level in hash tree */ #define SKEIN_T1_POS_BIT_PAD SKEIN_T1_BIT(119) /* bit 119 : partial final input byte */ #define SKEIN_T1_POS_BLK_TYPE SKEIN_T1_BIT(120) /* bits 120..125: type field */ #define SKEIN_T1_POS_FIRST SKEIN_T1_BIT(126) /* bits 126 : first block flag */ #define SKEIN_T1_POS_FINAL SKEIN_T1_BIT(127) /* bit 127 : final block flag */ /* tweak word T[1]: flag bit definition(s) */ #define SKEIN_T1_FLAG_FIRST (((u64b_t) 1 ) << SKEIN_T1_POS_FIRST) #define SKEIN_T1_FLAG_FINAL (((u64b_t) 1 ) << SKEIN_T1_POS_FINAL) #define SKEIN_T1_FLAG_BIT_PAD (((u64b_t) 1 ) << SKEIN_T1_POS_BIT_PAD) /* tweak word T[1]: tree level bit field mask */ #define SKEIN_T1_TREE_LVL_MASK (((u64b_t)0x7F) << SKEIN_T1_POS_TREE_LVL) #define SKEIN_T1_TREE_LEVEL(n) (((u64b_t) (n)) << SKEIN_T1_POS_TREE_LVL) /* tweak word T[1]: block type field */ #define SKEIN_BLK_TYPE_KEY ( 0) /* key, for MAC and KDF */ #define SKEIN_BLK_TYPE_CFG ( 4) /* configuration block */ #define SKEIN_BLK_TYPE_PERS ( 8) /* personalization string */ #define SKEIN_BLK_TYPE_PK (12) /* public key (for digital signature hashing) */ #define SKEIN_BLK_TYPE_KDF (16) /* key identifier for KDF */ #define SKEIN_BLK_TYPE_NONCE (20) /* nonce for PRNG */ #define SKEIN_BLK_TYPE_MSG (48) /* message processing */ #define SKEIN_BLK_TYPE_OUT (63) /* output stage */ #define SKEIN_BLK_TYPE_MASK (63) /* bit field mask */ #define SKEIN_T1_BLK_TYPE(T) (((u64b_t) (SKEIN_BLK_TYPE_##T)) << SKEIN_T1_POS_BLK_TYPE) #define SKEIN_T1_BLK_TYPE_KEY SKEIN_T1_BLK_TYPE(KEY) /* key, for MAC and KDF */ #define SKEIN_T1_BLK_TYPE_CFG SKEIN_T1_BLK_TYPE(CFG) /* configuration block */ #define SKEIN_T1_BLK_TYPE_PERS SKEIN_T1_BLK_TYPE(PERS) /* personalization string */ #define SKEIN_T1_BLK_TYPE_PK SKEIN_T1_BLK_TYPE(PK) /* public key (for digital signature hashing) */ #define SKEIN_T1_BLK_TYPE_KDF SKEIN_T1_BLK_TYPE(KDF) /* key identifier for KDF */ #define SKEIN_T1_BLK_TYPE_NONCE SKEIN_T1_BLK_TYPE(NONCE)/* nonce for PRNG */ #define SKEIN_T1_BLK_TYPE_MSG SKEIN_T1_BLK_TYPE(MSG) /* message processing */ #define SKEIN_T1_BLK_TYPE_OUT SKEIN_T1_BLK_TYPE(OUT) /* output stage */ #define SKEIN_T1_BLK_TYPE_MASK SKEIN_T1_BLK_TYPE(MASK) /* field bit mask */ #define SKEIN_T1_BLK_TYPE_CFG_FINAL (SKEIN_T1_BLK_TYPE_CFG | SKEIN_T1_FLAG_FINAL) #define SKEIN_T1_BLK_TYPE_OUT_FINAL (SKEIN_T1_BLK_TYPE_OUT | SKEIN_T1_FLAG_FINAL) #define SKEIN_VERSION (1) #ifndef SKEIN_ID_STRING_LE /* allow compile-time personalization */ #define SKEIN_ID_STRING_LE (0x33414853) /* "SHA3" (little-endian)*/ #endif #define SKEIN_MK_64(hi32,lo32) ((lo32) + (((u64b_t) (hi32)) << 32)) #define SKEIN_SCHEMA_VER SKEIN_MK_64(SKEIN_VERSION,SKEIN_ID_STRING_LE) #define SKEIN_KS_PARITY SKEIN_MK_64(0x55555555,0x55555555) #define SKEIN_CFG_STR_LEN (4*8) /* bit field definitions in config block treeInfo word */ #define SKEIN_CFG_TREE_LEAF_SIZE_POS ( 0) #define SKEIN_CFG_TREE_NODE_SIZE_POS ( 8) #define SKEIN_CFG_TREE_MAX_LEVEL_POS (16) #define SKEIN_CFG_TREE_LEAF_SIZE_MSK ((u64b_t) 0xFF) << SKEIN_CFG_TREE_LEAF_SIZE_POS) #define SKEIN_CFG_TREE_NODE_SIZE_MSK ((u64b_t) 0xFF) << SKEIN_CFG_TREE_NODE_SIZE_POS) #define SKEIN_CFG_TREE_MAX_LEVEL_MSK ((u64b_t) 0xFF) << SKEIN_CFG_TREE_MAX_LEVEL_POS) #define SKEIN_CFG_TREE_INFO_SEQUENTIAL (0) /* use as treeInfo in InitExt() call for sequential processing */ #define SKEIN_CFG_TREE_INFO(leaf,node,maxLevel) ((u64b_t) ((leaf) | ((node) << 8) | ((maxLevel) << 16))) /* ** Skein macros for getting/setting tweak words, etc. ** These are useful for partial input bytes, hash tree init/update, etc. **/ #define Skein_Get_Tweak(ctxPtr,TWK_NUM) ((ctxPtr)->h.T[TWK_NUM]) #define Skein_Set_Tweak(ctxPtr,TWK_NUM,tVal) {(ctxPtr)->h.T[TWK_NUM] = (tVal);} #define Skein_Get_T0(ctxPtr) Skein_Get_Tweak(ctxPtr,0) #define Skein_Get_T1(ctxPtr) Skein_Get_Tweak(ctxPtr,1) #define Skein_Set_T0(ctxPtr,T0) Skein_Set_Tweak(ctxPtr,0,T0) #define Skein_Set_T1(ctxPtr,T1) Skein_Set_Tweak(ctxPtr,1,T1) /* set both tweak words at once */ #define Skein_Set_T0_T1(ctxPtr,T0,T1) \ { \ Skein_Set_T0(ctxPtr,(T0)); \ Skein_Set_T1(ctxPtr,(T1)); \ } #define Skein_Set_Type(ctxPtr,BLK_TYPE) \ Skein_Set_T1(ctxPtr,SKEIN_T1_BLK_TYPE_##BLK_TYPE) /* set up for starting with a new type: h.T[0]=0; h.T[1] = NEW_TYPE; h.bCnt=0; */ #define Skein_Start_New_Type(ctxPtr,BLK_TYPE) \ { Skein_Set_T0_T1(ctxPtr,0,SKEIN_T1_FLAG_FIRST | SKEIN_T1_BLK_TYPE_##BLK_TYPE); (ctxPtr)->h.bCnt=0; } #define Skein_Clear_First_Flag(hdr) { (hdr).T[1] &= ~SKEIN_T1_FLAG_FIRST; } #define Skein_Set_Bit_Pad_Flag(hdr) { (hdr).T[1] |= SKEIN_T1_FLAG_BIT_PAD; } #define Skein_Set_Tree_Level(hdr,height) { (hdr).T[1] |= SKEIN_T1_TREE_LEVEL(height);} /***************************************************************** ** "Internal" Skein definitions for debugging and error checking ******************************************************************/ #ifdef SKEIN_DEBUG /* examine/display intermediate values? */ #include "skein_debug.h" #else /* default is no callouts */ #define Skein_Show_Block(bits,ctx,X,blkPtr,wPtr,ksEvenPtr,ksOddPtr) #define Skein_Show_Round(bits,ctx,r,X) #define Skein_Show_R_Ptr(bits,ctx,r,X_ptr) #define Skein_Show_Final(bits,ctx,cnt,outPtr) #define Skein_Show_Key(bits,ctx,key,keyBytes) #endif #ifndef SKEIN_ERR_CHECK /* run-time checks (e.g., bad params, uninitialized context)? */ #define Skein_Assert(x,retCode)/* default: ignore all Asserts, for performance */ #define Skein_assert(x) #elif defined(SKEIN_ASSERT) #include #define Skein_Assert(x,retCode) assert(x) #define Skein_assert(x) assert(x) #else #include #define Skein_Assert(x,retCode) { if (!(x)) return retCode; } /* caller error */ #define Skein_assert(x) assert(x) /* internal error */ #endif /***************************************************************** ** Skein block function constants (shared across Ref and Opt code) ******************************************************************/ enum { /* Skein_256 round rotation constants */ R_256_0_0= 5, R_256_0_1=56, R_256_1_0=36, R_256_1_1=28, R_256_2_0=13, R_256_2_1=46, R_256_3_0=58, R_256_3_1=44, R_256_4_0=26, R_256_4_1=20, R_256_5_0=53, R_256_5_1=35, R_256_6_0=11, R_256_6_1=42, R_256_7_0=59, R_256_7_1=50, #ifndef ONLY_SKEIN_256 /* Skein_512 round rotation constants */ R_512_0_0=38, R_512_0_1=30, R_512_0_2=50, R_512_0_3=53, R_512_1_0=48, R_512_1_1=20, R_512_1_2=43, R_512_1_3=31, R_512_2_0=34, R_512_2_1=14, R_512_2_2=15, R_512_2_3=27, R_512_3_0=26, R_512_3_1=12, R_512_3_2=58, R_512_3_3= 7, R_512_4_0=33, R_512_4_1=49, R_512_4_2= 8, R_512_4_3=42, R_512_5_0=39, R_512_5_1=27, R_512_5_2=41, R_512_5_3=14, R_512_6_0=29, R_512_6_1=26, R_512_6_2=11, R_512_6_3= 9, R_512_7_0=33, R_512_7_1=51, R_512_7_2=39, R_512_7_3=35, /* Skein1024 round rotation constants */ R1024_0_0=55, R1024_0_1=43, R1024_0_2=37, R1024_0_3=40, R1024_0_4=16, R1024_0_5=22, R1024_0_6=38, R1024_0_7=12, R1024_1_0=25, R1024_1_1=25, R1024_1_2=46, R1024_1_3=13, R1024_1_4=14, R1024_1_5=13, R1024_1_6=52, R1024_1_7=57, R1024_2_0=33, R1024_2_1= 8, R1024_2_2=18, R1024_2_3=57, R1024_2_4=21, R1024_2_5=12, R1024_2_6=32, R1024_2_7=54, R1024_3_0=34, R1024_3_1=43, R1024_3_2=25, R1024_3_3=60, R1024_3_4=44, R1024_3_5= 9, R1024_3_6=59, R1024_3_7=34, R1024_4_0=28, R1024_4_1= 7, R1024_4_2=47, R1024_4_3=48, R1024_4_4=51, R1024_4_5= 9, R1024_4_6=35, R1024_4_7=41, R1024_5_0=17, R1024_5_1= 6, R1024_5_2=18, R1024_5_3=25, R1024_5_4=43, R1024_5_5=42, R1024_5_6=40, R1024_5_7=15, R1024_6_0=58, R1024_6_1= 7, R1024_6_2=32, R1024_6_3=45, R1024_6_4=19, R1024_6_5=18, R1024_6_6= 2, R1024_6_7=56, R1024_7_0=47, R1024_7_1=49, R1024_7_2=27, R1024_7_3=58, R1024_7_4=37, R1024_7_5=48, R1024_7_6=53, R1024_7_7=56 #endif }; #ifndef SKEIN_ROUNDS #define SKEIN_256_ROUNDS_TOTAL (72) /* number of rounds for the different block sizes */ #define SKEIN_512_ROUNDS_TOTAL (72) #define SKEIN1024_ROUNDS_TOTAL (80) #else /* allow command-line define in range 8*(5..14) */ #define SKEIN_256_ROUNDS_TOTAL (8*((((SKEIN_ROUNDS/100) + 5) % 10) + 5)) #define SKEIN_512_ROUNDS_TOTAL (8*((((SKEIN_ROUNDS/ 10) + 5) % 10) + 5)) #define SKEIN1024_ROUNDS_TOTAL (8*((((SKEIN_ROUNDS ) + 5) % 10) + 5)) #endif #endif /* ifndef _SKEIN_H_ */ ekeyd-1.1.5/device/skein/skein_port.h0000664000175000017500000001114511215461720015332 0ustar pmpm#ifndef _SKEIN_PORT_H_ #define _SKEIN_PORT_H_ /******************************************************************* ** ** Platform-specific definitions for Skein hash function. ** ** Source code author: Doug Whiting, 2008. ** ** This algorithm and source code is released to the public domain. ** ** Many thanks to Brian Gladman for his portable header files. ** ** To port Skein to an "unsupported" platform, change the definitions ** in this file appropriately. ** ********************************************************************/ #include "brg_types.h" /* get integer type definitions */ typedef unsigned int uint_t; /* native unsigned integer */ typedef uint_8t u08b_t; /* 8-bit unsigned integer */ typedef uint_64t u64b_t; /* 64-bit unsigned integer */ #ifndef RotL_64 #define RotL_64(x,N) (((x) << (N)) | ((x) >> (64-(N)))) #endif /* * Skein is "natively" little-endian (unlike SHA-xxx), for optimal * performance on x86 CPUs. The Skein code requires the following * definitions for dealing with endianness: * * SKEIN_NEED_SWAP: 0 for little-endian, 1 for big-endian * Skein_Put64_LSB_First * Skein_Get64_LSB_First * Skein_Swap64 * * If SKEIN_NEED_SWAP is defined at compile time, it is used here * along with the portable versions of Put64/Get64/Swap64, which * are slow in general. * * Otherwise, an "auto-detect" of endianness is attempted below. * If the default handling doesn't work well, the user may insert * platform-specific code instead (e.g., for big-endian CPUs). * */ #ifndef SKEIN_NEED_SWAP /* compile-time "override" for endianness? */ #include "brg_endian.h" /* get endianness selection */ #if PLATFORM_BYTE_ORDER == IS_BIG_ENDIAN /* here for big-endian CPUs */ #define SKEIN_NEED_SWAP (1) #elif PLATFORM_BYTE_ORDER == IS_LITTLE_ENDIAN /* here for x86 and x86-64 CPUs (and other detected little-endian CPUs) */ #define SKEIN_NEED_SWAP (0) #if PLATFORM_MUST_ALIGN == 0 /* ok to use "fast" versions? */ #define Skein_Put64_LSB_First(dst08,src64,bCnt) memcpy(dst08,src64,bCnt) #define Skein_Get64_LSB_First(dst64,src08,wCnt) memcpy(dst64,src08,8*(wCnt)) #endif #else #error "Skein needs endianness setting!" #endif #endif /* ifndef SKEIN_NEED_SWAP */ /* ****************************************************************** * Provide any definitions still needed. ****************************************************************** */ #ifndef Skein_Swap64 /* swap for big-endian, nop for little-endian */ #if SKEIN_NEED_SWAP #define Skein_Swap64(w64) \ ( (( ((u64b_t)(w64)) & 0xFF) << 56) | \ (((((u64b_t)(w64)) >> 8) & 0xFF) << 48) | \ (((((u64b_t)(w64)) >>16) & 0xFF) << 40) | \ (((((u64b_t)(w64)) >>24) & 0xFF) << 32) | \ (((((u64b_t)(w64)) >>32) & 0xFF) << 24) | \ (((((u64b_t)(w64)) >>40) & 0xFF) << 16) | \ (((((u64b_t)(w64)) >>48) & 0xFF) << 8) | \ (((((u64b_t)(w64)) >>56) & 0xFF) ) ) #else #define Skein_Swap64(w64) (w64) #endif #endif /* ifndef Skein_Swap64 */ #ifndef Skein_Put64_LSB_First void Skein_Put64_LSB_First(u08b_t *dst,const u64b_t *src,size_t bCnt) #ifdef SKEIN_PORT_CODE /* instantiate the function code here? */ { /* this version is fully portable (big-endian or little-endian), but slow */ size_t n; for (n=0;n>3] >> (8*(n&7))); } #else ; /* output only the function prototype */ #endif #endif /* ifndef Skein_Put64_LSB_First */ #ifndef Skein_Get64_LSB_First void Skein_Get64_LSB_First(u64b_t *dst,const u08b_t *src,size_t wCnt) #ifdef SKEIN_PORT_CODE /* instantiate the function code here? */ { /* this version is fully portable (big-endian or little-endian), but slow */ size_t n; for (n=0;n<8*wCnt;n+=8) dst[n/8] = (((u64b_t) src[n ]) ) + (((u64b_t) src[n+1]) << 8) + (((u64b_t) src[n+2]) << 16) + (((u64b_t) src[n+3]) << 24) + (((u64b_t) src[n+4]) << 32) + (((u64b_t) src[n+5]) << 40) + (((u64b_t) src[n+6]) << 48) + (((u64b_t) src[n+7]) << 56) ; } #else ; /* output only the function prototype */ #endif #endif /* ifndef Skein_Get64_LSB_First */ #ifdef SKEIN_DEBUG_STM32 #include "hw_config.h" #define DEBUGLED Toggle_LED() #else #define DEBUGLED do { } while (0) #endif #endif /* ifndef _SKEIN_PORT_H_ */ ekeyd-1.1.5/device/skein/brg_types.h0000664000175000017500000001541111213205660015150 0ustar pmpm/* --------------------------------------------------------------------------- Copyright (c) 1998-2006, Brian Gladman, Worcester, UK. All rights reserved. LICENSE TERMS The free distribution and use of this software in both source and binary form is allowed (with or without changes) provided that: 1. distributions of this source code include the above copyright notice, this list of conditions and the following disclaimer; 2. distributions in binary form include the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other associated materials; 3. the copyright holder's name is not used to endorse products built using this software without specific written permission. ALTERNATIVELY, provided that this notice is retained in full, this product may be distributed under the terms of the GNU General Public License (GPL), in which case the provisions of the GPL apply INSTEAD OF those given above. DISCLAIMER This software is provided 'as is' with no explicit or implied warranties in respect of its properties, including, but not limited to, correctness and/or fitness for purpose. --------------------------------------------------------------------------- Issue 09/09/2006 The unsigned integer types defined here are of the form uint_t where is the length of the type; for example, the unsigned 32-bit type is 'uint_32t'. These are NOT the same as the 'C99 integer types' that are defined in the inttypes.h and stdint.h headers since attempts to use these types have shown that support for them is still highly variable. However, since the latter are of the form uint_t, a regular expression search and replace (in VC++ search on 'uint_{:z}t' and replace with 'uint\1_t') can be used to convert the types used here to the C99 standard types. */ #ifndef BRG_TYPES_H #define BRG_TYPES_H #if defined(__cplusplus) extern "C" { #endif #include #ifndef BRG_UI8 # define BRG_UI8 # if UCHAR_MAX == 255u typedef unsigned char uint_8t; # else # error Please define uint_8t as an 8-bit unsigned integer type in brg_types.h # endif #endif #ifndef BRG_UI16 # define BRG_UI16 # if USHRT_MAX == 65535u typedef unsigned short uint_16t; # else # error Please define uint_16t as a 16-bit unsigned short type in brg_types.h # endif #endif #ifndef BRG_UI32 # define BRG_UI32 # if UINT_MAX == 4294967295u # define li_32(h) 0x##h##u typedef unsigned int uint_32t; # elif ULONG_MAX == 4294967295u # define li_32(h) 0x##h##ul typedef unsigned long uint_32t; # elif defined( _CRAY ) # error This code needs 32-bit data types, which Cray machines do not provide # else # error Please define uint_32t as a 32-bit unsigned integer type in brg_types.h # endif #endif #ifndef BRG_UI64 # if defined( __BORLANDC__ ) && !defined( __MSDOS__ ) # define BRG_UI64 # define li_64(h) 0x##h##ui64 typedef unsigned __int64 uint_64t; # elif defined( _MSC_VER ) && ( _MSC_VER < 1300 ) /* 1300 == VC++ 7.0 */ # define BRG_UI64 # define li_64(h) 0x##h##ui64 typedef unsigned __int64 uint_64t; # elif defined( __sun ) && defined(ULONG_MAX) && ULONG_MAX == 0xfffffffful # define BRG_UI64 # define li_64(h) 0x##h##ull typedef unsigned long long uint_64t; # elif defined( UINT_MAX ) && UINT_MAX > 4294967295u # if UINT_MAX == 18446744073709551615u # define BRG_UI64 # define li_64(h) 0x##h##u typedef unsigned int uint_64t; # endif # elif defined( ULONG_MAX ) && ULONG_MAX > 4294967295u # if ULONG_MAX == 18446744073709551615ul # define BRG_UI64 # define li_64(h) 0x##h##ul typedef unsigned long uint_64t; # endif # elif defined( ULLONG_MAX ) && ULLONG_MAX > 4294967295u # if ULLONG_MAX == 18446744073709551615ull # define BRG_UI64 # define li_64(h) 0x##h##ull typedef unsigned long long uint_64t; # endif # elif defined( ULONG_LONG_MAX ) && ULONG_LONG_MAX > 4294967295u # if ULONG_LONG_MAX == 18446744073709551615ull # define BRG_UI64 # define li_64(h) 0x##h##ull typedef unsigned long long uint_64t; # endif # elif defined(__GNUC__) /* DLW: avoid mingw problem with -ansi */ # define BRG_UI64 # define li_64(h) 0x##h##ull typedef unsigned long long uint_64t; # endif #endif #if defined( NEED_UINT_64T ) && !defined( BRG_UI64 ) # error Please define uint_64t as an unsigned 64 bit type in brg_types.h #endif #ifndef RETURN_VALUES # define RETURN_VALUES # if defined( DLL_EXPORT ) # if defined( _MSC_VER ) || defined ( __INTEL_COMPILER ) # define VOID_RETURN __declspec( dllexport ) void __stdcall # define INT_RETURN __declspec( dllexport ) int __stdcall # elif defined( __GNUC__ ) # define VOID_RETURN __declspec( __dllexport__ ) void # define INT_RETURN __declspec( __dllexport__ ) int # else # error Use of the DLL is only available on the Microsoft, Intel and GCC compilers # endif # elif defined( DLL_IMPORT ) # if defined( _MSC_VER ) || defined ( __INTEL_COMPILER ) # define VOID_RETURN __declspec( dllimport ) void __stdcall # define INT_RETURN __declspec( dllimport ) int __stdcall # elif defined( __GNUC__ ) # define VOID_RETURN __declspec( __dllimport__ ) void # define INT_RETURN __declspec( __dllimport__ ) int # else # error Use of the DLL is only available on the Microsoft, Intel and GCC compilers # endif # elif defined( __WATCOMC__ ) # define VOID_RETURN void __cdecl # define INT_RETURN int __cdecl # else # define VOID_RETURN void # define INT_RETURN int # endif #endif /* These defines are used to declare buffers in a way that allows faster operations on longer variables to be used. In all these defines 'size' must be a power of 2 and >= 8 dec_unit_type(size,x) declares a variable 'x' of length 'size' bits dec_bufr_type(size,bsize,x) declares a buffer 'x' of length 'bsize' bytes defined as an array of variables each of 'size' bits (bsize must be a multiple of size / 8) ptr_cast(x,size) casts a pointer to a pointer to a varaiable of length 'size' bits */ #define ui_type(size) uint_##size##t #define dec_unit_type(size,x) typedef ui_type(size) x #define dec_bufr_type(size,bsize,x) typedef ui_type(size) x[bsize / (size >> 3)] #define ptr_cast(x,size) ((ui_type(size)*)(x)) #if defined(__cplusplus) } #endif #endif ekeyd-1.1.5/device/skein/skein_block.c0000664000175000017500000006447011242640363015446 0ustar pmpm/*********************************************************************** ** ** Implementation of the Skein block functions. ** ** Source code author: Doug Whiting, 2008. ** ** This algorithm and source code is released to the public domain. ** ** Compile-time switches: ** ** SKEIN_USE_ASM -- set bits (256/512/1024) to select which ** versions use ASM code for block processing ** [default: use C for all block sizes] ** ************************************************************************/ #include #include "skein.h" #ifndef SKEIN_USE_ASM #define SKEIN_USE_ASM (0) /* default is all C code (no ASM) */ #endif #ifndef SKEIN_LOOP #define SKEIN_LOOP 101 /* default: unroll 256 and 512, but not 1024 */ #endif #define BLK_BITS (WCNT*64) /* some useful definitions for code here */ #define KW_TWK_BASE (0) #define KW_KEY_BASE (3) #define ks (kw + KW_KEY_BASE) #define ts (kw + KW_TWK_BASE) #ifdef SKEIN_DEBUG #define DebugSaveTweak(ctx) { ctx->h.T[0] = ts[0]; ctx->h.T[1] = ts[1]; } #else #define DebugSaveTweak(ctx) #endif /***************************** Skein_256 ******************************/ #if !(SKEIN_USE_ASM & 256) void Skein_256_Process_Block(Skein_256_Ctxt_t *ctx,const u08b_t *blkPtr,size_t blkCnt,size_t byteCntAdd) { /* do it in C */ enum { WCNT = SKEIN_256_STATE_WORDS }; #undef RCNT #define RCNT (SKEIN_256_ROUNDS_TOTAL/8) #ifdef SKEIN_LOOP /* configure how much to unroll the loop */ #define SKEIN_UNROLL_256 (((SKEIN_LOOP)/100)%10) #else #define SKEIN_UNROLL_256 (0) #endif #if SKEIN_UNROLL_256 #if (RCNT % SKEIN_UNROLL_256) #error "Invalid SKEIN_UNROLL_256" /* sanity check on unroll count */ #endif size_t r; u64b_t kw[WCNT+4+RCNT*2]; /* key schedule words : chaining vars + tweak + "rotation"*/ #else u64b_t kw[WCNT+4]; /* key schedule words : chaining vars + tweak */ #endif u64b_t X0,X1,X2,X3; /* local copy of context vars, for speed */ u64b_t w [WCNT]; /* local copy of input block */ #ifdef SKEIN_DEBUG const u64b_t *Xptr[4]; /* use for debugging (help compiler put Xn in registers) */ Xptr[0] = &X0; Xptr[1] = &X1; Xptr[2] = &X2; Xptr[3] = &X3; #endif Skein_assert(blkCnt != 0); /* never call with blkCnt == 0! */ ts[0] = ctx->h.T[0]; ts[1] = ctx->h.T[1]; do { /* this implementation only supports 2**64 input bytes (no carry out here) */ ts[0] += byteCntAdd; /* update processed length */ /* precompute the key schedule for this block */ ks[0] = ctx->X[0]; ks[1] = ctx->X[1]; ks[2] = ctx->X[2]; ks[3] = ctx->X[3]; ks[4] = ks[0] ^ ks[1] ^ ks[2] ^ ks[3] ^ SKEIN_KS_PARITY; ts[2] = ts[0] ^ ts[1]; Skein_Get64_LSB_First(w,blkPtr,WCNT); /* get input block in little-endian format */ DebugSaveTweak(ctx); Skein_Show_Block(BLK_BITS,&ctx->h,ctx->X,blkPtr,w,ks,ts); X0 = w[0] + ks[0]; /* do the first full key injection */ X1 = w[1] + ks[1] + ts[0]; X2 = w[2] + ks[2] + ts[1]; X3 = w[3] + ks[3]; Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INITIAL,Xptr); /* show starting state values */ blkPtr += SKEIN_256_BLOCK_BYTES; /* run the rounds */ #define Round256(p0,p1,p2,p3,ROT,rNum) \ X##p0 += X##p1; X##p1 = RotL_64(X##p1,ROT##_0); X##p1 ^= X##p0; \ X##p2 += X##p3; X##p3 = RotL_64(X##p3,ROT##_1); X##p3 ^= X##p2; \ #if SKEIN_UNROLL_256 == 0 #define R256(p0,p1,p2,p3,ROT,rNum) /* fully unrolled */ \ Round256(p0,p1,p2,p3,ROT,rNum) \ Skein_Show_R_Ptr(BLK_BITS,&ctx->h,rNum,Xptr); #define I256(R) \ X0 += ks[((R)+1) % 5]; /* inject the key schedule value */ \ X1 += ks[((R)+2) % 5] + ts[((R)+1) % 3]; \ X2 += ks[((R)+3) % 5] + ts[((R)+2) % 3]; \ X3 += ks[((R)+4) % 5] + (R)+1; \ Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INJECT,Xptr); #else /* looping version */ #define R256(p0,p1,p2,p3,ROT,rNum) \ Round256(p0,p1,p2,p3,ROT,rNum) \ Skein_Show_R_Ptr(BLK_BITS,&ctx->h,4*(r-1)+rNum,Xptr); #define I256(R) \ X0 += ks[r+(R)+0]; /* inject the key schedule value */ \ X1 += ks[r+(R)+1] + ts[r+(R)+0]; \ X2 += ks[r+(R)+2] + ts[r+(R)+1]; \ X3 += ks[r+(R)+3] + r+(R) ; \ ks[r + (R)+4 ] = ks[r+(R)-1]; /* rotate key schedule */\ ts[r + (R)+2 ] = ts[r+(R)-1]; \ Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INJECT,Xptr); for (r=1;r < 2*RCNT;r+=2*SKEIN_UNROLL_256) /* loop thru it */ #endif { #define R256_8_rounds(R) \ DEBUGLED; \ R256(0,1,2,3,R_256_0,8*(R) + 1); \ R256(0,3,2,1,R_256_1,8*(R) + 2); \ R256(0,1,2,3,R_256_2,8*(R) + 3); \ R256(0,3,2,1,R_256_3,8*(R) + 4); \ I256(2*(R)); \ R256(0,1,2,3,R_256_4,8*(R) + 5); \ R256(0,3,2,1,R_256_5,8*(R) + 6); \ R256(0,1,2,3,R_256_6,8*(R) + 7); \ R256(0,3,2,1,R_256_7,8*(R) + 8); \ I256(2*(R)+1); R256_8_rounds( 0); #define R256_Unroll_R(NN) ((SKEIN_UNROLL_256 == 0 && SKEIN_256_ROUNDS_TOTAL/8 > (NN)) || (SKEIN_UNROLL_256 > (NN))) #if R256_Unroll_R( 1) R256_8_rounds( 1); #endif #if R256_Unroll_R( 2) R256_8_rounds( 2); #endif #if R256_Unroll_R( 3) R256_8_rounds( 3); #endif #if R256_Unroll_R( 4) R256_8_rounds( 4); #endif #if R256_Unroll_R( 5) R256_8_rounds( 5); #endif #if R256_Unroll_R( 6) R256_8_rounds( 6); #endif #if R256_Unroll_R( 7) R256_8_rounds( 7); #endif #if R256_Unroll_R( 8) R256_8_rounds( 8); #endif #if R256_Unroll_R( 9) R256_8_rounds( 9); #endif #if R256_Unroll_R(10) R256_8_rounds(10); #endif #if R256_Unroll_R(11) R256_8_rounds(11); #endif #if R256_Unroll_R(12) R256_8_rounds(12); #endif #if R256_Unroll_R(13) R256_8_rounds(13); #endif #if R256_Unroll_R(14) R256_8_rounds(14); #endif #if (SKEIN_UNROLL_256 > 14) #error "need more unrolling in Skein_256_Process_Block" #endif } /* do the final "feedforward" xor, update context chaining vars */ ctx->X[0] = X0 ^ w[0]; ctx->X[1] = X1 ^ w[1]; ctx->X[2] = X2 ^ w[2]; ctx->X[3] = X3 ^ w[3]; Skein_Show_Round(BLK_BITS,&ctx->h,SKEIN_RND_FEED_FWD,ctx->X); ts[1] &= ~SKEIN_T1_FLAG_FIRST; } while (--blkCnt); ctx->h.T[0] = ts[0]; ctx->h.T[1] = ts[1]; } #if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF) size_t Skein_256_Process_Block_CodeSize(void) { return ((u08b_t *) Skein_256_Process_Block_CodeSize) - ((u08b_t *) Skein_256_Process_Block); } uint_t Skein_256_Unroll_Cnt(void) { return SKEIN_UNROLL_256; } #endif #endif #ifndef ONLY_SKEIN_256 /***************************** Skein_512 ******************************/ #if !(SKEIN_USE_ASM & 512) void Skein_512_Process_Block(Skein_512_Ctxt_t *ctx,const u08b_t *blkPtr,size_t blkCnt,size_t byteCntAdd) { /* do it in C */ enum { WCNT = SKEIN_512_STATE_WORDS }; #undef RCNT #define RCNT (SKEIN_512_ROUNDS_TOTAL/8) #ifdef SKEIN_LOOP /* configure how much to unroll the loop */ #define SKEIN_UNROLL_512 (((SKEIN_LOOP)/10)%10) #else #define SKEIN_UNROLL_512 (0) #endif #if SKEIN_UNROLL_512 #if (RCNT % SKEIN_UNROLL_512) #error "Invalid SKEIN_UNROLL_512" /* sanity check on unroll count */ #endif size_t r; u64b_t kw[WCNT+4+RCNT*2]; /* key schedule words : chaining vars + tweak + "rotation"*/ #else u64b_t kw[WCNT+4]; /* key schedule words : chaining vars + tweak */ #endif u64b_t X0,X1,X2,X3,X4,X5,X6,X7; /* local copy of vars, for speed */ u64b_t w [WCNT]; /* local copy of input block */ #ifdef SKEIN_DEBUG const u64b_t *Xptr[8]; /* use for debugging (help compiler put Xn in registers) */ Xptr[0] = &X0; Xptr[1] = &X1; Xptr[2] = &X2; Xptr[3] = &X3; Xptr[4] = &X4; Xptr[5] = &X5; Xptr[6] = &X6; Xptr[7] = &X7; #endif Skein_assert(blkCnt != 0); /* never call with blkCnt == 0! */ ts[0] = ctx->h.T[0]; ts[1] = ctx->h.T[1]; do { /* this implementation only supports 2**64 input bytes (no carry out here) */ ts[0] += byteCntAdd; /* update processed length */ /* precompute the key schedule for this block */ ks[0] = ctx->X[0]; ks[1] = ctx->X[1]; ks[2] = ctx->X[2]; ks[3] = ctx->X[3]; ks[4] = ctx->X[4]; ks[5] = ctx->X[5]; ks[6] = ctx->X[6]; ks[7] = ctx->X[7]; ks[8] = ks[0] ^ ks[1] ^ ks[2] ^ ks[3] ^ ks[4] ^ ks[5] ^ ks[6] ^ ks[7] ^ SKEIN_KS_PARITY; ts[2] = ts[0] ^ ts[1]; Skein_Get64_LSB_First(w,blkPtr,WCNT); /* get input block in little-endian format */ DebugSaveTweak(ctx); Skein_Show_Block(BLK_BITS,&ctx->h,ctx->X,blkPtr,w,ks,ts); X0 = w[0] + ks[0]; /* do the first full key injection */ X1 = w[1] + ks[1]; X2 = w[2] + ks[2]; X3 = w[3] + ks[3]; X4 = w[4] + ks[4]; X5 = w[5] + ks[5] + ts[0]; X6 = w[6] + ks[6] + ts[1]; X7 = w[7] + ks[7]; blkPtr += SKEIN_512_BLOCK_BYTES; Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INITIAL,Xptr); /* run the rounds */ #define Round512(p0,p1,p2,p3,p4,p5,p6,p7,ROT,rNum) \ X##p0 += X##p1; X##p1 = RotL_64(X##p1,ROT##_0); X##p1 ^= X##p0; \ X##p2 += X##p3; X##p3 = RotL_64(X##p3,ROT##_1); X##p3 ^= X##p2; \ X##p4 += X##p5; X##p5 = RotL_64(X##p5,ROT##_2); X##p5 ^= X##p4; \ X##p6 += X##p7; X##p7 = RotL_64(X##p7,ROT##_3); X##p7 ^= X##p6; \ #if SKEIN_UNROLL_512 == 0 #define R512(p0,p1,p2,p3,p4,p5,p6,p7,ROT,rNum) /* unrolled */ \ Round512(p0,p1,p2,p3,p4,p5,p6,p7,ROT,rNum) \ Skein_Show_R_Ptr(BLK_BITS,&ctx->h,rNum,Xptr); #define I512(R) \ X0 += ks[((R)+1) % 9]; /* inject the key schedule value */ \ X1 += ks[((R)+2) % 9]; \ X2 += ks[((R)+3) % 9]; \ X3 += ks[((R)+4) % 9]; \ X4 += ks[((R)+5) % 9]; \ X5 += ks[((R)+6) % 9] + ts[((R)+1) % 3]; \ X6 += ks[((R)+7) % 9] + ts[((R)+2) % 3]; \ X7 += ks[((R)+8) % 9] + (R)+1; \ Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INJECT,Xptr); #else /* looping version */ #define R512(p0,p1,p2,p3,p4,p5,p6,p7,ROT,rNum) \ Round512(p0,p1,p2,p3,p4,p5,p6,p7,ROT,rNum) \ Skein_Show_R_Ptr(BLK_BITS,&ctx->h,4*(r-1)+rNum,Xptr); #define I512(R) \ X0 += ks[r+(R)+0]; /* inject the key schedule value */ \ X1 += ks[r+(R)+1]; \ X2 += ks[r+(R)+2]; \ X3 += ks[r+(R)+3]; \ X4 += ks[r+(R)+4]; \ X5 += ks[r+(R)+5] + ts[r+(R)+0]; \ X6 += ks[r+(R)+6] + ts[r+(R)+1]; \ X7 += ks[r+(R)+7] + r+(R) ; \ ks[r + (R)+8] = ks[r+(R)-1]; /* rotate key schedule */ \ ts[r + (R)+2] = ts[r+(R)-1]; \ Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INJECT,Xptr); for (r=1;r < 2*RCNT;r+=2*SKEIN_UNROLL_512) /* loop thru it */ #endif /* end of looped code definitions */ { #define R512_8_rounds(R) /* do 8 full rounds */ \ R512(0,1,2,3,4,5,6,7,R_512_0,8*(R)+ 1); \ R512(2,1,4,7,6,5,0,3,R_512_1,8*(R)+ 2); \ R512(4,1,6,3,0,5,2,7,R_512_2,8*(R)+ 3); \ R512(6,1,0,7,2,5,4,3,R_512_3,8*(R)+ 4); \ I512(2*(R)); \ R512(0,1,2,3,4,5,6,7,R_512_4,8*(R)+ 5); \ R512(2,1,4,7,6,5,0,3,R_512_5,8*(R)+ 6); \ R512(4,1,6,3,0,5,2,7,R_512_6,8*(R)+ 7); \ R512(6,1,0,7,2,5,4,3,R_512_7,8*(R)+ 8); \ I512(2*(R)+1); /* and key injection */ R512_8_rounds( 0); #define R512_Unroll_R(NN) ((SKEIN_UNROLL_512 == 0 && SKEIN_512_ROUNDS_TOTAL/8 > (NN)) || (SKEIN_UNROLL_512 > (NN))) #if R512_Unroll_R( 1) R512_8_rounds( 1); #endif #if R512_Unroll_R( 2) R512_8_rounds( 2); #endif #if R512_Unroll_R( 3) R512_8_rounds( 3); #endif #if R512_Unroll_R( 4) R512_8_rounds( 4); #endif #if R512_Unroll_R( 5) R512_8_rounds( 5); #endif #if R512_Unroll_R( 6) R512_8_rounds( 6); #endif #if R512_Unroll_R( 7) R512_8_rounds( 7); #endif #if R512_Unroll_R( 8) R512_8_rounds( 8); #endif #if R512_Unroll_R( 9) R512_8_rounds( 9); #endif #if R512_Unroll_R(10) R512_8_rounds(10); #endif #if R512_Unroll_R(11) R512_8_rounds(11); #endif #if R512_Unroll_R(12) R512_8_rounds(12); #endif #if R512_Unroll_R(13) R512_8_rounds(13); #endif #if R512_Unroll_R(14) R512_8_rounds(14); #endif #if (SKEIN_UNROLL_512 > 14) #error "need more unrolling in Skein_512_Process_Block" #endif } /* do the final "feedforward" xor, update context chaining vars */ ctx->X[0] = X0 ^ w[0]; ctx->X[1] = X1 ^ w[1]; ctx->X[2] = X2 ^ w[2]; ctx->X[3] = X3 ^ w[3]; ctx->X[4] = X4 ^ w[4]; ctx->X[5] = X5 ^ w[5]; ctx->X[6] = X6 ^ w[6]; ctx->X[7] = X7 ^ w[7]; Skein_Show_Round(BLK_BITS,&ctx->h,SKEIN_RND_FEED_FWD,ctx->X); ts[1] &= ~SKEIN_T1_FLAG_FIRST; } while (--blkCnt); ctx->h.T[0] = ts[0]; ctx->h.T[1] = ts[1]; } #if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF) size_t Skein_512_Process_Block_CodeSize(void) { return ((u08b_t *) Skein_512_Process_Block_CodeSize) - ((u08b_t *) Skein_512_Process_Block); } uint_t Skein_512_Unroll_Cnt(void) { return SKEIN_UNROLL_512; } #endif #endif /***************************** Skein1024 ******************************/ #if !(SKEIN_USE_ASM & 1024) void Skein1024_Process_Block(Skein1024_Ctxt_t *ctx,const u08b_t *blkPtr,size_t blkCnt,size_t byteCntAdd) { /* do it in C, always looping (unrolled is bigger AND slower!) */ enum { WCNT = SKEIN1024_STATE_WORDS }; #undef RCNT #define RCNT (SKEIN1024_ROUNDS_TOTAL/8) #ifdef SKEIN_LOOP /* configure how much to unroll the loop */ #define SKEIN_UNROLL_1024 ((SKEIN_LOOP)%10) #else #define SKEIN_UNROLL_1024 (0) #endif #if (SKEIN_UNROLL_1024 != 0) #if (RCNT % SKEIN_UNROLL_1024) #error "Invalid SKEIN_UNROLL_1024" /* sanity check on unroll count */ #endif size_t r; u64b_t kw[WCNT+4+RCNT*2]; /* key schedule words : chaining vars + tweak + "rotation"*/ #else u64b_t kw[WCNT+4]; /* key schedule words : chaining vars + tweak */ #endif u64b_t X00,X01,X02,X03,X04,X05,X06,X07, /* local copy of vars, for speed */ X08,X09,X10,X11,X12,X13,X14,X15; u64b_t w [WCNT]; /* local copy of input block */ #ifdef SKEIN_DEBUG const u64b_t *Xptr[16]; /* use for debugging (help compiler put Xn in registers) */ Xptr[ 0] = &X00; Xptr[ 1] = &X01; Xptr[ 2] = &X02; Xptr[ 3] = &X03; Xptr[ 4] = &X04; Xptr[ 5] = &X05; Xptr[ 6] = &X06; Xptr[ 7] = &X07; Xptr[ 8] = &X08; Xptr[ 9] = &X09; Xptr[10] = &X10; Xptr[11] = &X11; Xptr[12] = &X12; Xptr[13] = &X13; Xptr[14] = &X14; Xptr[15] = &X15; #endif Skein_assert(blkCnt != 0); /* never call with blkCnt == 0! */ ts[0] = ctx->h.T[0]; ts[1] = ctx->h.T[1]; do { /* this implementation only supports 2**64 input bytes (no carry out here) */ ts[0] += byteCntAdd; /* update processed length */ /* precompute the key schedule for this block */ ks[ 0] = ctx->X[ 0]; ks[ 1] = ctx->X[ 1]; ks[ 2] = ctx->X[ 2]; ks[ 3] = ctx->X[ 3]; ks[ 4] = ctx->X[ 4]; ks[ 5] = ctx->X[ 5]; ks[ 6] = ctx->X[ 6]; ks[ 7] = ctx->X[ 7]; ks[ 8] = ctx->X[ 8]; ks[ 9] = ctx->X[ 9]; ks[10] = ctx->X[10]; ks[11] = ctx->X[11]; ks[12] = ctx->X[12]; ks[13] = ctx->X[13]; ks[14] = ctx->X[14]; ks[15] = ctx->X[15]; ks[16] = ks[ 0] ^ ks[ 1] ^ ks[ 2] ^ ks[ 3] ^ ks[ 4] ^ ks[ 5] ^ ks[ 6] ^ ks[ 7] ^ ks[ 8] ^ ks[ 9] ^ ks[10] ^ ks[11] ^ ks[12] ^ ks[13] ^ ks[14] ^ ks[15] ^ SKEIN_KS_PARITY; ts[2] = ts[0] ^ ts[1]; Skein_Get64_LSB_First(w,blkPtr,WCNT); /* get input block in little-endian format */ DebugSaveTweak(ctx); Skein_Show_Block(BLK_BITS,&ctx->h,ctx->X,blkPtr,w,ks,ts); X00 = w[ 0] + ks[ 0]; /* do the first full key injection */ X01 = w[ 1] + ks[ 1]; X02 = w[ 2] + ks[ 2]; X03 = w[ 3] + ks[ 3]; X04 = w[ 4] + ks[ 4]; X05 = w[ 5] + ks[ 5]; X06 = w[ 6] + ks[ 6]; X07 = w[ 7] + ks[ 7]; X08 = w[ 8] + ks[ 8]; X09 = w[ 9] + ks[ 9]; X10 = w[10] + ks[10]; X11 = w[11] + ks[11]; X12 = w[12] + ks[12]; X13 = w[13] + ks[13] + ts[0]; X14 = w[14] + ks[14] + ts[1]; X15 = w[15] + ks[15]; Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INITIAL,Xptr); #define Round1024(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,pA,pB,pC,pD,pE,pF,ROT,rNum) \ X##p0 += X##p1; X##p1 = RotL_64(X##p1,ROT##_0); X##p1 ^= X##p0; \ X##p2 += X##p3; X##p3 = RotL_64(X##p3,ROT##_1); X##p3 ^= X##p2; \ X##p4 += X##p5; X##p5 = RotL_64(X##p5,ROT##_2); X##p5 ^= X##p4; \ X##p6 += X##p7; X##p7 = RotL_64(X##p7,ROT##_3); X##p7 ^= X##p6; \ X##p8 += X##p9; X##p9 = RotL_64(X##p9,ROT##_4); X##p9 ^= X##p8; \ X##pA += X##pB; X##pB = RotL_64(X##pB,ROT##_5); X##pB ^= X##pA; \ X##pC += X##pD; X##pD = RotL_64(X##pD,ROT##_6); X##pD ^= X##pC; \ X##pE += X##pF; X##pF = RotL_64(X##pF,ROT##_7); X##pF ^= X##pE; \ #if SKEIN_UNROLL_1024 == 0 #define R1024(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,pA,pB,pC,pD,pE,pF,ROT,rn) \ Round1024(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,pA,pB,pC,pD,pE,pF,ROT,rn) \ Skein_Show_R_Ptr(BLK_BITS,&ctx->h,rn,Xptr); #define I1024(R) \ X00 += ks[((R)+ 1) % 17]; /* inject the key schedule value */ \ X01 += ks[((R)+ 2) % 17]; \ X02 += ks[((R)+ 3) % 17]; \ X03 += ks[((R)+ 4) % 17]; \ X04 += ks[((R)+ 5) % 17]; \ X05 += ks[((R)+ 6) % 17]; \ X06 += ks[((R)+ 7) % 17]; \ X07 += ks[((R)+ 8) % 17]; \ X08 += ks[((R)+ 9) % 17]; \ X09 += ks[((R)+10) % 17]; \ X10 += ks[((R)+11) % 17]; \ X11 += ks[((R)+12) % 17]; \ X12 += ks[((R)+13) % 17]; \ X13 += ks[((R)+14) % 17] + ts[((R)+1) % 3]; \ X14 += ks[((R)+15) % 17] + ts[((R)+2) % 3]; \ X15 += ks[((R)+16) % 17] + (R)+1; \ Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INJECT,Xptr); #else /* looping version */ #define R1024(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,pA,pB,pC,pD,pE,pF,ROT,rn) \ Round1024(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,pA,pB,pC,pD,pE,pF,ROT,rn) \ Skein_Show_R_Ptr(BLK_BITS,&ctx->h,4*(r-1)+rn,Xptr); #define I1024(R) \ X00 += ks[r+(R)+ 0]; /* inject the key schedule value */ \ X01 += ks[r+(R)+ 1]; \ X02 += ks[r+(R)+ 2]; \ X03 += ks[r+(R)+ 3]; \ X04 += ks[r+(R)+ 4]; \ X05 += ks[r+(R)+ 5]; \ X06 += ks[r+(R)+ 6]; \ X07 += ks[r+(R)+ 7]; \ X08 += ks[r+(R)+ 8]; \ X09 += ks[r+(R)+ 9]; \ X10 += ks[r+(R)+10]; \ X11 += ks[r+(R)+11]; \ X12 += ks[r+(R)+12]; \ X13 += ks[r+(R)+13] + ts[r+(R)+0]; \ X14 += ks[r+(R)+14] + ts[r+(R)+1]; \ X15 += ks[r+(R)+15] + r+(R) ; \ ks[r + (R)+16] = ks[r+(R)-1]; /* rotate key schedule */ \ ts[r + (R)+ 2] = ts[r+(R)-1]; \ Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INJECT,Xptr); for (r=1;r <= 2*RCNT;r+=2*SKEIN_UNROLL_1024) /* loop thru it */ #endif { #define R1024_8_rounds(R) /* do 8 full rounds */ \ R1024(00,01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,R1024_0,8*(R) + 1); \ R1024(00,09,02,13,06,11,04,15,10,07,12,03,14,05,08,01,R1024_1,8*(R) + 2); \ R1024(00,07,02,05,04,03,06,01,12,15,14,13,08,11,10,09,R1024_2,8*(R) + 3); \ R1024(00,15,02,11,06,13,04,09,14,01,08,05,10,03,12,07,R1024_3,8*(R) + 4); \ I1024(2*(R)); \ R1024(00,01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,R1024_4,8*(R) + 5); \ R1024(00,09,02,13,06,11,04,15,10,07,12,03,14,05,08,01,R1024_5,8*(R) + 6); \ R1024(00,07,02,05,04,03,06,01,12,15,14,13,08,11,10,09,R1024_6,8*(R) + 7); \ R1024(00,15,02,11,06,13,04,09,14,01,08,05,10,03,12,07,R1024_7,8*(R) + 8); \ I1024(2*(R)+1); R1024_8_rounds( 0); #define R1024_Unroll_R(NN) ((SKEIN_UNROLL_1024 == 0 && SKEIN1024_ROUNDS_TOTAL/8 > (NN)) || (SKEIN_UNROLL_1024 > (NN))) #if R1024_Unroll_R( 1) R1024_8_rounds( 1); #endif #if R1024_Unroll_R( 2) R1024_8_rounds( 2); #endif #if R1024_Unroll_R( 3) R1024_8_rounds( 3); #endif #if R1024_Unroll_R( 4) R1024_8_rounds( 4); #endif #if R1024_Unroll_R( 5) R1024_8_rounds( 5); #endif #if R1024_Unroll_R( 6) R1024_8_rounds( 6); #endif #if R1024_Unroll_R( 7) R1024_8_rounds( 7); #endif #if R1024_Unroll_R( 8) R1024_8_rounds( 8); #endif #if R1024_Unroll_R( 9) R1024_8_rounds( 9); #endif #if R1024_Unroll_R(10) R1024_8_rounds(10); #endif #if R1024_Unroll_R(11) R1024_8_rounds(11); #endif #if R1024_Unroll_R(12) R1024_8_rounds(12); #endif #if R1024_Unroll_R(13) R1024_8_rounds(13); #endif #if R1024_Unroll_R(14) R1024_8_rounds(14); #endif #if (SKEIN_UNROLL_1024 > 14) #error "need more unrolling in Skein_1024_Process_Block" #endif } /* do the final "feedforward" xor, update context chaining vars */ ctx->X[ 0] = X00 ^ w[ 0]; ctx->X[ 1] = X01 ^ w[ 1]; ctx->X[ 2] = X02 ^ w[ 2]; ctx->X[ 3] = X03 ^ w[ 3]; ctx->X[ 4] = X04 ^ w[ 4]; ctx->X[ 5] = X05 ^ w[ 5]; ctx->X[ 6] = X06 ^ w[ 6]; ctx->X[ 7] = X07 ^ w[ 7]; ctx->X[ 8] = X08 ^ w[ 8]; ctx->X[ 9] = X09 ^ w[ 9]; ctx->X[10] = X10 ^ w[10]; ctx->X[11] = X11 ^ w[11]; ctx->X[12] = X12 ^ w[12]; ctx->X[13] = X13 ^ w[13]; ctx->X[14] = X14 ^ w[14]; ctx->X[15] = X15 ^ w[15]; Skein_Show_Round(BLK_BITS,&ctx->h,SKEIN_RND_FEED_FWD,ctx->X); ts[1] &= ~SKEIN_T1_FLAG_FIRST; blkPtr += SKEIN1024_BLOCK_BYTES; } while (--blkCnt); ctx->h.T[0] = ts[0]; ctx->h.T[1] = ts[1]; } #if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF) size_t Skein1024_Process_Block_CodeSize(void) { return ((u08b_t *) Skein1024_Process_Block_CodeSize) - ((u08b_t *) Skein1024_Process_Block); } uint_t Skein1024_Unroll_Cnt(void) { return SKEIN_UNROLL_1024; } #endif #endif #endif ekeyd-1.1.5/device/skein/skein.c0000664000175000017500000010547211217665420014275 0ustar pmpm/*********************************************************************** ** ** Implementation of the Skein hash function. ** ** Source code author: Doug Whiting, 2008. ** ** This algorithm and source code is released to the public domain. ** ************************************************************************/ #define SKEIN_PORT_CODE /* instantiate any code in skein_port.h */ #include /* get the memcpy/memset functions */ #include "skein.h" /* get the Skein API definitions */ #include "skein_iv.h" /* get precomputed IVs */ /*****************************************************************/ /* External function to process blkCnt (nonzero) full block(s) of data. */ void Skein_256_Process_Block(Skein_256_Ctxt_t *ctx,const u08b_t *blkPtr,size_t blkCnt,size_t byteCntAdd); void Skein_512_Process_Block(Skein_512_Ctxt_t *ctx,const u08b_t *blkPtr,size_t blkCnt,size_t byteCntAdd); void Skein1024_Process_Block(Skein1024_Ctxt_t *ctx,const u08b_t *blkPtr,size_t blkCnt,size_t byteCntAdd); /*****************************************************************/ /* 256-bit Skein */ /*****************************************************************/ /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ /* init the context for a straight hashing operation */ int Skein_256_Init(Skein_256_Ctxt_t *ctx, size_t hashBitLen) { union { u08b_t b[SKEIN_256_STATE_BYTES]; u64b_t w[SKEIN_256_STATE_WORDS]; } cfg; /* config block */ Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN); ctx->h.hashBitLen = hashBitLen; /* output hash bit count */ switch (hashBitLen) { /* use pre-computed values, where available */ #ifndef SKEIN_NO_PRECOMP case 256: memcpy(ctx->X,SKEIN_256_IV_256,sizeof(ctx->X)); break; #ifndef ONLY_SKEIN_256_256 case 224: memcpy(ctx->X,SKEIN_256_IV_224,sizeof(ctx->X)); break; case 160: memcpy(ctx->X,SKEIN_256_IV_160,sizeof(ctx->X)); break; case 128: memcpy(ctx->X,SKEIN_256_IV_128,sizeof(ctx->X)); break; #endif #endif default: /* here if there is no precomputed IV value available */ /* build/process the config block, type == CONFIG (could be precomputed) */ Skein_Start_New_Type(ctx,CFG_FINAL); /* set tweaks: T0=0; T1=CFG | FINAL */ cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER); /* set the schema, version */ cfg.w[1] = Skein_Swap64(hashBitLen); /* hash result length in bits */ cfg.w[2] = Skein_Swap64(SKEIN_CFG_TREE_INFO_SEQUENTIAL); memset(&cfg.w[3],0,sizeof(cfg) - 3*sizeof(cfg.w[0])); /* zero pad config block */ /* compute the initial chaining values from config block */ memset(ctx->X,0,sizeof(ctx->X)); /* zero the chaining variables */ Skein_256_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN); break; } /* The chaining vars ctx->X are now initialized for the given hashBitLen. */ /* Set up to process the data message portion of the hash (default) */ Skein_Start_New_Type(ctx,MSG); /* T0=0, T1= MSG type */ return SKEIN_SUCCESS; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ /* init the context for a MAC and/or tree hash operation */ /* [identical to Skein_256_Init() when keyBytes == 0 && treeInfo == SKEIN_CFG_TREE_INFO_SEQUENTIAL] */ int Skein_256_InitExt(Skein_256_Ctxt_t *ctx,size_t hashBitLen,u64b_t treeInfo, const u08b_t *key, size_t keyBytes) { union { u08b_t b[SKEIN_256_STATE_BYTES]; u64b_t w[SKEIN_256_STATE_WORDS]; } cfg; /* config block */ Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN); Skein_Assert(keyBytes == 0 || key != NULL,SKEIN_FAIL); /* compute the initial chaining values ctx->X[], based on key */ if (keyBytes == 0) /* is there a key? */ { memset(ctx->X,0,sizeof(ctx->X)); /* no key: use all zeroes as key for config block */ } else /* here to pre-process a key */ { Skein_assert(sizeof(cfg.b) >= sizeof(ctx->X)); /* do a mini-Init right here */ ctx->h.hashBitLen=8*sizeof(ctx->X); /* set output hash bit count = state size */ Skein_Start_New_Type(ctx,KEY); /* set tweaks: T0 = 0; T1 = KEY type */ memset(ctx->X,0,sizeof(ctx->X)); /* zero the initial chaining variables */ Skein_256_Update(ctx,key,keyBytes); /* hash the key */ Skein_256_Final_Pad(ctx,cfg.b); /* put result into cfg.b[] */ memcpy(ctx->X,cfg.b,sizeof(cfg.b)); /* copy over into ctx->X[] */ #if SKEIN_NEED_SWAP { uint_t i; for (i=0;iX[i] = Skein_Swap64(ctx->X[i]); } #endif } /* build/process the config block, type == CONFIG (could be precomputed for each key) */ ctx->h.hashBitLen = hashBitLen; /* output hash bit count */ Skein_Start_New_Type(ctx,CFG_FINAL); memset(&cfg.w,0,sizeof(cfg.w)); /* pre-pad cfg.w[] with zeroes */ cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER); cfg.w[1] = Skein_Swap64(hashBitLen); /* hash result length in bits */ cfg.w[2] = Skein_Swap64(treeInfo); /* tree hash config info (or SKEIN_CFG_TREE_INFO_SEQUENTIAL) */ Skein_Show_Key(256,&ctx->h,key,keyBytes); /* compute the initial chaining values from config block */ Skein_256_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN); /* The chaining vars ctx->X are now initialized */ /* Set up to process the data message portion of the hash (default) */ ctx->h.bCnt = 0; /* buffer b[] starts out empty */ Skein_Start_New_Type(ctx,MSG); return SKEIN_SUCCESS; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ /* process the input bytes */ int Skein_256_Update(Skein_256_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt) { size_t n; Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ /* process full blocks, if any */ if (msgByteCnt + ctx->h.bCnt > SKEIN_256_BLOCK_BYTES) { if (ctx->h.bCnt) /* finish up any buffered message data */ { n = SKEIN_256_BLOCK_BYTES - ctx->h.bCnt; /* # bytes free in buffer b[] */ if (n) { Skein_assert(n < msgByteCnt); /* check on our logic here */ memcpy(&ctx->b[ctx->h.bCnt],msg,n); msgByteCnt -= n; msg += n; ctx->h.bCnt += n; } Skein_assert(ctx->h.bCnt == SKEIN_256_BLOCK_BYTES); Skein_256_Process_Block(ctx,ctx->b,1,SKEIN_256_BLOCK_BYTES); ctx->h.bCnt = 0; } /* now process any remaining full blocks, directly from input message data */ if (msgByteCnt > SKEIN_256_BLOCK_BYTES) { n = (msgByteCnt-1) / SKEIN_256_BLOCK_BYTES; /* number of full blocks to process */ Skein_256_Process_Block(ctx,msg,n,SKEIN_256_BLOCK_BYTES); msgByteCnt -= n * SKEIN_256_BLOCK_BYTES; msg += n * SKEIN_256_BLOCK_BYTES; } Skein_assert(ctx->h.bCnt == 0); } /* copy any remaining source message data bytes into b[] */ if (msgByteCnt) { Skein_assert(msgByteCnt + ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES); memcpy(&ctx->b[ctx->h.bCnt],msg,msgByteCnt); ctx->h.bCnt += msgByteCnt; } return SKEIN_SUCCESS; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ /* finalize the hash computation and output the result */ int Skein_256_Final(Skein_256_Ctxt_t *ctx, u08b_t *hashVal) { size_t i,n,byteCnt; u64b_t X[SKEIN_256_STATE_WORDS]; Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */ if (ctx->h.bCnt < SKEIN_256_BLOCK_BYTES) /* zero pad b[] if necessary */ memset(&ctx->b[ctx->h.bCnt],0,SKEIN_256_BLOCK_BYTES - ctx->h.bCnt); Skein_256_Process_Block(ctx,ctx->b,1,ctx->h.bCnt); /* process the final block */ /* now output the result */ byteCnt = (ctx->h.hashBitLen + 7) >> 3; /* total number of output bytes */ /* run Threefish in "counter mode" to generate output */ memset(ctx->b,0,sizeof(ctx->b)); /* zero out b[], so it can hold the counter */ memcpy(X,ctx->X,sizeof(X)); /* keep a local copy of counter mode "key" */ for (i=0;i*SKEIN_256_BLOCK_BYTES < byteCnt;i++) { ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */ Skein_Start_New_Type(ctx,OUT_FINAL); Skein_256_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */ n = byteCnt - i*SKEIN_256_BLOCK_BYTES; /* number of output bytes left to go */ if (n >= SKEIN_256_BLOCK_BYTES) n = SKEIN_256_BLOCK_BYTES; Skein_Put64_LSB_First(hashVal+i*SKEIN_256_BLOCK_BYTES,ctx->X,n); /* "output" the ctr mode bytes */ Skein_Show_Final(256,&ctx->h,n,hashVal+i*SKEIN_256_BLOCK_BYTES); memcpy(ctx->X,X,sizeof(X)); /* restore the counter mode key for next time */ } return SKEIN_SUCCESS; } #if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF) size_t Skein_256_API_CodeSize(void) { return ((u08b_t *) Skein_256_API_CodeSize) - ((u08b_t *) Skein_256_Init); } #endif #ifndef ONLY_SKEIN_256 /*****************************************************************/ /* 512-bit Skein */ /*****************************************************************/ /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ /* init the context for a straight hashing operation */ int Skein_512_Init(Skein_512_Ctxt_t *ctx, size_t hashBitLen) { union { u08b_t b[SKEIN_512_STATE_BYTES]; u64b_t w[SKEIN_512_STATE_WORDS]; } cfg; /* config block */ Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN); ctx->h.hashBitLen = hashBitLen; /* output hash bit count */ switch (hashBitLen) { /* use pre-computed values, where available */ #ifndef SKEIN_NO_PRECOMP case 512: memcpy(ctx->X,SKEIN_512_IV_512,sizeof(ctx->X)); break; case 384: memcpy(ctx->X,SKEIN_512_IV_384,sizeof(ctx->X)); break; case 256: memcpy(ctx->X,SKEIN_512_IV_256,sizeof(ctx->X)); break; case 224: memcpy(ctx->X,SKEIN_512_IV_224,sizeof(ctx->X)); break; #endif default: /* here if there is no precomputed IV value available */ /* build/process the config block, type == CONFIG (could be precomputed) */ Skein_Start_New_Type(ctx,CFG_FINAL); /* set tweaks: T0=0; T1=CFG | FINAL */ cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER); /* set the schema, version */ cfg.w[1] = Skein_Swap64(hashBitLen); /* hash result length in bits */ cfg.w[2] = Skein_Swap64(SKEIN_CFG_TREE_INFO_SEQUENTIAL); memset(&cfg.w[3],0,sizeof(cfg) - 3*sizeof(cfg.w[0])); /* zero pad config block */ /* compute the initial chaining values from config block */ memset(ctx->X,0,sizeof(ctx->X)); /* zero the chaining variables */ Skein_512_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN); break; } /* The chaining vars ctx->X are now initialized for the given hashBitLen. */ /* Set up to process the data message portion of the hash (default) */ Skein_Start_New_Type(ctx,MSG); /* T0=0, T1= MSG type */ return SKEIN_SUCCESS; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ /* init the context for a MAC and/or tree hash operation */ /* [identical to Skein_512_Init() when keyBytes == 0 && treeInfo == SKEIN_CFG_TREE_INFO_SEQUENTIAL] */ int Skein_512_InitExt(Skein_512_Ctxt_t *ctx,size_t hashBitLen,u64b_t treeInfo, const u08b_t *key, size_t keyBytes) { union { u08b_t b[SKEIN_512_STATE_BYTES]; u64b_t w[SKEIN_512_STATE_WORDS]; } cfg; /* config block */ Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN); Skein_Assert(keyBytes == 0 || key != NULL,SKEIN_FAIL); /* compute the initial chaining values ctx->X[], based on key */ if (keyBytes == 0) /* is there a key? */ { memset(ctx->X,0,sizeof(ctx->X)); /* no key: use all zeroes as key for config block */ } else /* here to pre-process a key */ { Skein_assert(sizeof(cfg.b) >= sizeof(ctx->X)); /* do a mini-Init right here */ ctx->h.hashBitLen=8*sizeof(ctx->X); /* set output hash bit count = state size */ Skein_Start_New_Type(ctx,KEY); /* set tweaks: T0 = 0; T1 = KEY type */ memset(ctx->X,0,sizeof(ctx->X)); /* zero the initial chaining variables */ Skein_512_Update(ctx,key,keyBytes); /* hash the key */ Skein_512_Final_Pad(ctx,cfg.b); /* put result into cfg.b[] */ memcpy(ctx->X,cfg.b,sizeof(cfg.b)); /* copy over into ctx->X[] */ #if SKEIN_NEED_SWAP { uint_t i; for (i=0;iX[i] = Skein_Swap64(ctx->X[i]); } #endif } /* build/process the config block, type == CONFIG (could be precomputed for each key) */ ctx->h.hashBitLen = hashBitLen; /* output hash bit count */ Skein_Start_New_Type(ctx,CFG_FINAL); memset(&cfg.w,0,sizeof(cfg.w)); /* pre-pad cfg.w[] with zeroes */ cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER); cfg.w[1] = Skein_Swap64(hashBitLen); /* hash result length in bits */ cfg.w[2] = Skein_Swap64(treeInfo); /* tree hash config info (or SKEIN_CFG_TREE_INFO_SEQUENTIAL) */ Skein_Show_Key(512,&ctx->h,key,keyBytes); /* compute the initial chaining values from config block */ Skein_512_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN); /* The chaining vars ctx->X are now initialized */ /* Set up to process the data message portion of the hash (default) */ ctx->h.bCnt = 0; /* buffer b[] starts out empty */ Skein_Start_New_Type(ctx,MSG); return SKEIN_SUCCESS; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ /* process the input bytes */ int Skein_512_Update(Skein_512_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt) { size_t n; Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ /* process full blocks, if any */ if (msgByteCnt + ctx->h.bCnt > SKEIN_512_BLOCK_BYTES) { if (ctx->h.bCnt) /* finish up any buffered message data */ { n = SKEIN_512_BLOCK_BYTES - ctx->h.bCnt; /* # bytes free in buffer b[] */ if (n) { Skein_assert(n < msgByteCnt); /* check on our logic here */ memcpy(&ctx->b[ctx->h.bCnt],msg,n); msgByteCnt -= n; msg += n; ctx->h.bCnt += n; } Skein_assert(ctx->h.bCnt == SKEIN_512_BLOCK_BYTES); Skein_512_Process_Block(ctx,ctx->b,1,SKEIN_512_BLOCK_BYTES); ctx->h.bCnt = 0; } /* now process any remaining full blocks, directly from input message data */ if (msgByteCnt > SKEIN_512_BLOCK_BYTES) { n = (msgByteCnt-1) / SKEIN_512_BLOCK_BYTES; /* number of full blocks to process */ Skein_512_Process_Block(ctx,msg,n,SKEIN_512_BLOCK_BYTES); msgByteCnt -= n * SKEIN_512_BLOCK_BYTES; msg += n * SKEIN_512_BLOCK_BYTES; } Skein_assert(ctx->h.bCnt == 0); } /* copy any remaining source message data bytes into b[] */ if (msgByteCnt) { Skein_assert(msgByteCnt + ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES); memcpy(&ctx->b[ctx->h.bCnt],msg,msgByteCnt); ctx->h.bCnt += msgByteCnt; } return SKEIN_SUCCESS; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ /* finalize the hash computation and output the result */ int Skein_512_Final(Skein_512_Ctxt_t *ctx, u08b_t *hashVal) { size_t i,n,byteCnt; u64b_t X[SKEIN_512_STATE_WORDS]; Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */ if (ctx->h.bCnt < SKEIN_512_BLOCK_BYTES) /* zero pad b[] if necessary */ memset(&ctx->b[ctx->h.bCnt],0,SKEIN_512_BLOCK_BYTES - ctx->h.bCnt); Skein_512_Process_Block(ctx,ctx->b,1,ctx->h.bCnt); /* process the final block */ /* now output the result */ byteCnt = (ctx->h.hashBitLen + 7) >> 3; /* total number of output bytes */ /* run Threefish in "counter mode" to generate output */ memset(ctx->b,0,sizeof(ctx->b)); /* zero out b[], so it can hold the counter */ memcpy(X,ctx->X,sizeof(X)); /* keep a local copy of counter mode "key" */ for (i=0;i*SKEIN_512_BLOCK_BYTES < byteCnt;i++) { ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */ Skein_Start_New_Type(ctx,OUT_FINAL); Skein_512_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */ n = byteCnt - i*SKEIN_512_BLOCK_BYTES; /* number of output bytes left to go */ if (n >= SKEIN_512_BLOCK_BYTES) n = SKEIN_512_BLOCK_BYTES; Skein_Put64_LSB_First(hashVal+i*SKEIN_512_BLOCK_BYTES,ctx->X,n); /* "output" the ctr mode bytes */ Skein_Show_Final(512,&ctx->h,n,hashVal+i*SKEIN_512_BLOCK_BYTES); memcpy(ctx->X,X,sizeof(X)); /* restore the counter mode key for next time */ } return SKEIN_SUCCESS; } #if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF) size_t Skein_512_API_CodeSize(void) { return ((u08b_t *) Skein_512_API_CodeSize) - ((u08b_t *) Skein_512_Init); } #endif /*****************************************************************/ /* 1024-bit Skein */ /*****************************************************************/ /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ /* init the context for a straight hashing operation */ int Skein1024_Init(Skein1024_Ctxt_t *ctx, size_t hashBitLen) { union { u08b_t b[SKEIN1024_STATE_BYTES]; u64b_t w[SKEIN1024_STATE_WORDS]; } cfg; /* config block */ Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN); ctx->h.hashBitLen = hashBitLen; /* output hash bit count */ switch (hashBitLen) { /* use pre-computed values, where available */ #ifndef SKEIN_NO_PRECOMP case 512: memcpy(ctx->X,SKEIN1024_IV_512 ,sizeof(ctx->X)); break; case 384: memcpy(ctx->X,SKEIN1024_IV_384 ,sizeof(ctx->X)); break; case 1024: memcpy(ctx->X,SKEIN1024_IV_1024,sizeof(ctx->X)); break; #endif default: /* here if there is no precomputed IV value available */ /* build/process the config block, type == CONFIG (could be precomputed) */ Skein_Start_New_Type(ctx,CFG_FINAL); /* set tweaks: T0=0; T1=CFG | FINAL */ cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER); /* set the schema, version */ cfg.w[1] = Skein_Swap64(hashBitLen); /* hash result length in bits */ cfg.w[2] = Skein_Swap64(SKEIN_CFG_TREE_INFO_SEQUENTIAL); memset(&cfg.w[3],0,sizeof(cfg) - 3*sizeof(cfg.w[0])); /* zero pad config block */ /* compute the initial chaining values from config block */ memset(ctx->X,0,sizeof(ctx->X)); /* zero the chaining variables */ Skein1024_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN); break; } /* The chaining vars ctx->X are now initialized for the given hashBitLen. */ /* Set up to process the data message portion of the hash (default) */ Skein_Start_New_Type(ctx,MSG); /* T0=0, T1= MSG type */ return SKEIN_SUCCESS; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ /* init the context for a MAC and/or tree hash operation */ /* [identical to Skein1024_Init() when keyBytes == 0 && treeInfo == SKEIN_CFG_TREE_INFO_SEQUENTIAL] */ int Skein1024_InitExt(Skein1024_Ctxt_t *ctx,size_t hashBitLen,u64b_t treeInfo, const u08b_t *key, size_t keyBytes) { union { u08b_t b[SKEIN1024_STATE_BYTES]; u64b_t w[SKEIN1024_STATE_WORDS]; } cfg; /* config block */ Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN); Skein_Assert(keyBytes == 0 || key != NULL,SKEIN_FAIL); /* compute the initial chaining values ctx->X[], based on key */ if (keyBytes == 0) /* is there a key? */ { memset(ctx->X,0,sizeof(ctx->X)); /* no key: use all zeroes as key for config block */ } else /* here to pre-process a key */ { Skein_assert(sizeof(cfg.b) >= sizeof(ctx->X)); /* do a mini-Init right here */ ctx->h.hashBitLen=8*sizeof(ctx->X); /* set output hash bit count = state size */ Skein_Start_New_Type(ctx,KEY); /* set tweaks: T0 = 0; T1 = KEY type */ memset(ctx->X,0,sizeof(ctx->X)); /* zero the initial chaining variables */ Skein1024_Update(ctx,key,keyBytes); /* hash the key */ Skein1024_Final_Pad(ctx,cfg.b); /* put result into cfg.b[] */ memcpy(ctx->X,cfg.b,sizeof(cfg.b)); /* copy over into ctx->X[] */ #if SKEIN_NEED_SWAP { uint_t i; for (i=0;iX[i] = Skein_Swap64(ctx->X[i]); } #endif } /* build/process the config block, type == CONFIG (could be precomputed for each key) */ ctx->h.hashBitLen = hashBitLen; /* output hash bit count */ Skein_Start_New_Type(ctx,CFG_FINAL); memset(&cfg.w,0,sizeof(cfg.w)); /* pre-pad cfg.w[] with zeroes */ cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER); cfg.w[1] = Skein_Swap64(hashBitLen); /* hash result length in bits */ cfg.w[2] = Skein_Swap64(treeInfo); /* tree hash config info (or SKEIN_CFG_TREE_INFO_SEQUENTIAL) */ Skein_Show_Key(1024,&ctx->h,key,keyBytes); /* compute the initial chaining values from config block */ Skein1024_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN); /* The chaining vars ctx->X are now initialized */ /* Set up to process the data message portion of the hash (default) */ ctx->h.bCnt = 0; /* buffer b[] starts out empty */ Skein_Start_New_Type(ctx,MSG); return SKEIN_SUCCESS; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ /* process the input bytes */ int Skein1024_Update(Skein1024_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt) { size_t n; Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ /* process full blocks, if any */ if (msgByteCnt + ctx->h.bCnt > SKEIN1024_BLOCK_BYTES) { if (ctx->h.bCnt) /* finish up any buffered message data */ { n = SKEIN1024_BLOCK_BYTES - ctx->h.bCnt; /* # bytes free in buffer b[] */ if (n) { Skein_assert(n < msgByteCnt); /* check on our logic here */ memcpy(&ctx->b[ctx->h.bCnt],msg,n); msgByteCnt -= n; msg += n; ctx->h.bCnt += n; } Skein_assert(ctx->h.bCnt == SKEIN1024_BLOCK_BYTES); Skein1024_Process_Block(ctx,ctx->b,1,SKEIN1024_BLOCK_BYTES); ctx->h.bCnt = 0; } /* now process any remaining full blocks, directly from input message data */ if (msgByteCnt > SKEIN1024_BLOCK_BYTES) { n = (msgByteCnt-1) / SKEIN1024_BLOCK_BYTES; /* number of full blocks to process */ Skein1024_Process_Block(ctx,msg,n,SKEIN1024_BLOCK_BYTES); msgByteCnt -= n * SKEIN1024_BLOCK_BYTES; msg += n * SKEIN1024_BLOCK_BYTES; } Skein_assert(ctx->h.bCnt == 0); } /* copy any remaining source message data bytes into b[] */ if (msgByteCnt) { Skein_assert(msgByteCnt + ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES); memcpy(&ctx->b[ctx->h.bCnt],msg,msgByteCnt); ctx->h.bCnt += msgByteCnt; } return SKEIN_SUCCESS; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ /* finalize the hash computation and output the result */ int Skein1024_Final(Skein1024_Ctxt_t *ctx, u08b_t *hashVal) { size_t i,n,byteCnt; u64b_t X[SKEIN1024_STATE_WORDS]; Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */ if (ctx->h.bCnt < SKEIN1024_BLOCK_BYTES) /* zero pad b[] if necessary */ memset(&ctx->b[ctx->h.bCnt],0,SKEIN1024_BLOCK_BYTES - ctx->h.bCnt); Skein1024_Process_Block(ctx,ctx->b,1,ctx->h.bCnt); /* process the final block */ /* now output the result */ byteCnt = (ctx->h.hashBitLen + 7) >> 3; /* total number of output bytes */ /* run Threefish in "counter mode" to generate output */ memset(ctx->b,0,sizeof(ctx->b)); /* zero out b[], so it can hold the counter */ memcpy(X,ctx->X,sizeof(X)); /* keep a local copy of counter mode "key" */ for (i=0;i*SKEIN1024_BLOCK_BYTES < byteCnt;i++) { ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */ Skein_Start_New_Type(ctx,OUT_FINAL); Skein1024_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */ n = byteCnt - i*SKEIN1024_BLOCK_BYTES; /* number of output bytes left to go */ if (n >= SKEIN1024_BLOCK_BYTES) n = SKEIN1024_BLOCK_BYTES; Skein_Put64_LSB_First(hashVal+i*SKEIN1024_BLOCK_BYTES,ctx->X,n); /* "output" the ctr mode bytes */ Skein_Show_Final(1024,&ctx->h,n,hashVal+i*SKEIN1024_BLOCK_BYTES); memcpy(ctx->X,X,sizeof(X)); /* restore the counter mode key for next time */ } return SKEIN_SUCCESS; } #if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF) size_t Skein1024_API_CodeSize(void) { return ((u08b_t *) Skein1024_API_CodeSize) - ((u08b_t *) Skein1024_Init); } #endif #endif /**************** Functions to support MAC/tree hashing ***************/ /* (this code is identical for Optimized and Reference versions) */ /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ /* finalize the hash computation and output the block, no OUTPUT stage */ int Skein_256_Final_Pad(Skein_256_Ctxt_t *ctx, u08b_t *hashVal) { Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */ if (ctx->h.bCnt < SKEIN_256_BLOCK_BYTES) /* zero pad b[] if necessary */ memset(&ctx->b[ctx->h.bCnt],0,SKEIN_256_BLOCK_BYTES - ctx->h.bCnt); Skein_256_Process_Block(ctx,ctx->b,1,ctx->h.bCnt); /* process the final block */ Skein_Put64_LSB_First(hashVal,ctx->X,SKEIN_256_BLOCK_BYTES); /* "output" the state bytes */ return SKEIN_SUCCESS; } #ifndef ONLY_SKEIN_256 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ /* finalize the hash computation and output the block, no OUTPUT stage */ int Skein_512_Final_Pad(Skein_512_Ctxt_t *ctx, u08b_t *hashVal) { Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */ if (ctx->h.bCnt < SKEIN_512_BLOCK_BYTES) /* zero pad b[] if necessary */ memset(&ctx->b[ctx->h.bCnt],0,SKEIN_512_BLOCK_BYTES - ctx->h.bCnt); Skein_512_Process_Block(ctx,ctx->b,1,ctx->h.bCnt); /* process the final block */ Skein_Put64_LSB_First(hashVal,ctx->X,SKEIN_512_BLOCK_BYTES); /* "output" the state bytes */ return SKEIN_SUCCESS; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ /* finalize the hash computation and output the block, no OUTPUT stage */ int Skein1024_Final_Pad(Skein1024_Ctxt_t *ctx, u08b_t *hashVal) { Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */ if (ctx->h.bCnt < SKEIN1024_BLOCK_BYTES) /* zero pad b[] if necessary */ memset(&ctx->b[ctx->h.bCnt],0,SKEIN1024_BLOCK_BYTES - ctx->h.bCnt); Skein1024_Process_Block(ctx,ctx->b,1,ctx->h.bCnt); /* process the final block */ Skein_Put64_LSB_First(hashVal,ctx->X,SKEIN1024_BLOCK_BYTES); /* "output" the state bytes */ return SKEIN_SUCCESS; } #if SKEIN_TREE_HASH /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ /* just do the OUTPUT stage */ int Skein_256_Output(Skein_256_Ctxt_t *ctx, u08b_t *hashVal) { size_t i,n,byteCnt; u64b_t X[SKEIN_256_STATE_WORDS]; Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ /* now output the result */ byteCnt = (ctx->h.hashBitLen + 7) >> 3; /* total number of output bytes */ /* run Threefish in "counter mode" to generate output */ memset(ctx->b,0,sizeof(ctx->b)); /* zero out b[], so it can hold the counter */ memcpy(X,ctx->X,sizeof(X)); /* keep a local copy of counter mode "key" */ for (i=0;i*SKEIN_256_BLOCK_BYTES < byteCnt;i++) { ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */ Skein_Start_New_Type(ctx,OUT_FINAL); Skein_256_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */ n = byteCnt - i*SKEIN_256_BLOCK_BYTES; /* number of output bytes left to go */ if (n >= SKEIN_256_BLOCK_BYTES) n = SKEIN_256_BLOCK_BYTES; Skein_Put64_LSB_First(hashVal+i*SKEIN_256_BLOCK_BYTES,ctx->X,n); /* "output" the ctr mode bytes */ Skein_Show_Final(256,&ctx->h,n,hashVal+i*SKEIN_256_BLOCK_BYTES); memcpy(ctx->X,X,sizeof(X)); /* restore the counter mode key for next time */ } return SKEIN_SUCCESS; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ /* just do the OUTPUT stage */ int Skein_512_Output(Skein_512_Ctxt_t *ctx, u08b_t *hashVal) { size_t i,n,byteCnt; u64b_t X[SKEIN_512_STATE_WORDS]; Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ /* now output the result */ byteCnt = (ctx->h.hashBitLen + 7) >> 3; /* total number of output bytes */ /* run Threefish in "counter mode" to generate output */ memset(ctx->b,0,sizeof(ctx->b)); /* zero out b[], so it can hold the counter */ memcpy(X,ctx->X,sizeof(X)); /* keep a local copy of counter mode "key" */ for (i=0;i*SKEIN_512_BLOCK_BYTES < byteCnt;i++) { ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */ Skein_Start_New_Type(ctx,OUT_FINAL); Skein_512_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */ n = byteCnt - i*SKEIN_512_BLOCK_BYTES; /* number of output bytes left to go */ if (n >= SKEIN_512_BLOCK_BYTES) n = SKEIN_512_BLOCK_BYTES; Skein_Put64_LSB_First(hashVal+i*SKEIN_512_BLOCK_BYTES,ctx->X,n); /* "output" the ctr mode bytes */ Skein_Show_Final(256,&ctx->h,n,hashVal+i*SKEIN_512_BLOCK_BYTES); memcpy(ctx->X,X,sizeof(X)); /* restore the counter mode key for next time */ } return SKEIN_SUCCESS; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ /* just do the OUTPUT stage */ int Skein1024_Output(Skein1024_Ctxt_t *ctx, u08b_t *hashVal) { size_t i,n,byteCnt; u64b_t X[SKEIN1024_STATE_WORDS]; Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ /* now output the result */ byteCnt = (ctx->h.hashBitLen + 7) >> 3; /* total number of output bytes */ /* run Threefish in "counter mode" to generate output */ memset(ctx->b,0,sizeof(ctx->b)); /* zero out b[], so it can hold the counter */ memcpy(X,ctx->X,sizeof(X)); /* keep a local copy of counter mode "key" */ for (i=0;i*SKEIN1024_BLOCK_BYTES < byteCnt;i++) { ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */ Skein_Start_New_Type(ctx,OUT_FINAL); Skein1024_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */ n = byteCnt - i*SKEIN1024_BLOCK_BYTES; /* number of output bytes left to go */ if (n >= SKEIN1024_BLOCK_BYTES) n = SKEIN1024_BLOCK_BYTES; Skein_Put64_LSB_First(hashVal+i*SKEIN1024_BLOCK_BYTES,ctx->X,n); /* "output" the ctr mode bytes */ Skein_Show_Final(256,&ctx->h,n,hashVal+i*SKEIN1024_BLOCK_BYTES); memcpy(ctx->X,X,sizeof(X)); /* restore the counter mode key for next time */ } return SKEIN_SUCCESS; } #endif #endif ekeyd-1.1.5/device/skein/skein_iv.h0000664000175000017500000001344611217665420014777 0ustar pmpm#ifndef _SKEIN_IV_H_ #define _SKEIN_IV_H_ #include "skein.h" /* get Skein macros and types */ /* ***************** Pre-computed Skein IVs ******************* ** ** NOTE: these values are not "magic" constants, but ** are generated using the Threefish block function. ** They are pre-computed here only for speed; i.e., to ** avoid the need for a Threefish call during Init(). ** ** The IV for any fixed hash length may be pre-computed. ** Only the most common values are included here. ** ************************************************************ **/ #define MK_64 SKEIN_MK_64 #ifndef ONLY_SKEIN_256_256 /* blkSize = 256 bits. hashSize = 128 bits */ const u64b_t SKEIN_256_IV_128[] = { MK_64(0x302F7EA2,0x3D7FE2E1), MK_64(0xADE4683A,0x6913752B), MK_64(0x975CFABE,0xF208AB0A), MK_64(0x2AF4BA95,0xF831F55B) }; /* blkSize = 256 bits. hashSize = 160 bits */ const u64b_t SKEIN_256_IV_160[] = { MK_64(0xA38A0D80,0xA3687723), MK_64(0xB73CDB6A,0x5963FFC9), MK_64(0x9633E8EA,0x07A1B447), MK_64(0xCA0ED09E,0xC9529C22) }; /* blkSize = 256 bits. hashSize = 224 bits */ const u64b_t SKEIN_256_IV_224[] = { MK_64(0xB8092969,0x9AE0F431), MK_64(0xD340DC14,0xA06929DC), MK_64(0xAE866594,0xBDE4DC5A), MK_64(0x339767C2,0x5A60EA1D) }; #endif /* blkSize = 256 bits. hashSize = 256 bits */ const u64b_t SKEIN_256_IV_256[] = { MK_64(0x38851268,0x0E660046), MK_64(0x4B72D5DE,0xC5A8FF01), MK_64(0x281A9298,0xCA5EB3A5), MK_64(0x54CA5249,0xF46070C4) }; #ifndef ONLY_SKEIN_256 /* blkSize = 512 bits. hashSize = 128 bits */ const u64b_t SKEIN_512_IV_128[] = { MK_64(0x477DF9EF,0xAFC4F08A), MK_64(0x7A64D342,0x33660E14), MK_64(0x71653C44,0xCEBC89C5), MK_64(0x63D2A36D,0x65B0AB91), MK_64(0x52B93FB0,0x9782EA89), MK_64(0x20F36980,0x8B960829), MK_64(0xE8DF80FB,0x30303B9B), MK_64(0xB89D3902,0x1A476D1F) }; /* blkSize = 512 bits. hashSize = 160 bits */ const u64b_t SKEIN_512_IV_160[] = { MK_64(0x0045FA2C,0xAD913A2C), MK_64(0xF45C9A76,0xBF75CE81), MK_64(0x0ED758A9,0x3D1F266B), MK_64(0xC0E65E85,0x1EDCD67A), MK_64(0x1E024D51,0xF5E7583E), MK_64(0xA271F855,0x4E52B0E1), MK_64(0x5292867D,0x8AC674F9), MK_64(0xADA325FA,0x60C3B226) }; /* blkSize = 512 bits. hashSize = 224 bits */ const u64b_t SKEIN_512_IV_224[] = { MK_64(0xF2DAA169,0x8216CC98), MK_64(0x00E06A48,0x8983AE05), MK_64(0xC080CEA9,0x5948958F), MK_64(0x2A8F314B,0x57F4ADD1), MK_64(0xBCD06591,0x360A405A), MK_64(0xF81A11A1,0x02D91F70), MK_64(0x85C6FFA5,0x4810A739), MK_64(0x1E07AFE0,0x1802CE74) }; /* blkSize = 512 bits. hashSize = 256 bits */ const u64b_t SKEIN_512_IV_256[] = { MK_64(0x88C07F38,0xD4F95AD4), MK_64(0x3DF0D33A,0x8610E240), MK_64(0x3E243F6E,0xDB6FAC74), MK_64(0xBAC4F4CD,0xD7A90A24), MK_64(0xDF90FD1F,0xDEEEBA04), MK_64(0xA4F5796B,0xDB7FDDA8), MK_64(0xDA182FD2,0x964BC923), MK_64(0x55F76677,0xEF6961F9) }; /* blkSize = 512 bits. hashSize = 384 bits */ const u64b_t SKEIN_512_IV_384[] = { MK_64(0xE5BF4D02,0xBA62494C), MK_64(0x7AA1EABC,0xC3E6FC68), MK_64(0xBBE5FC26,0xE1038C5A), MK_64(0x53C9903E,0x8F88E9FA), MK_64(0xF30D8DDD,0xFB940C83), MK_64(0x500FDA3C,0x4865ABEC), MK_64(0x2226C67F,0x745BC5E7), MK_64(0x015DA800,0x77C639F7) }; /* blkSize = 512 bits. hashSize = 512 bits */ const u64b_t SKEIN_512_IV_512[] = { MK_64(0xA8D47980,0x544A6E32), MK_64(0x84751153,0x3E9B1A8A), MK_64(0x6FAEE870,0xD8E81A00), MK_64(0x58B0D9D6,0xCB557F92), MK_64(0x9BBC0051,0xDAC1D4E9), MK_64(0xB744E2B1,0xD189E7CA), MK_64(0x979350FA,0x709C5EF3), MK_64(0x0350125A,0x92067BCD) }; /* blkSize = 1024 bits. hashSize = 384 bits */ const u64b_t SKEIN1024_IV_384[] = { MK_64(0x7600B2E3,0x9FC73E48), MK_64(0x7A4543BB,0xECCD60E4), MK_64(0x8AB879D6,0x2F53E192), MK_64(0x14847919,0xA7F0AC6E), MK_64(0x4F774735,0xAA99CB7F), MK_64(0x607CF3C2,0x41760EE1), MK_64(0xC0BF6D7B,0xFF9F27DB), MK_64(0x7D321485,0x99342254), MK_64(0xE7231BB0,0xCDF9DD49), MK_64(0x641DE8E6,0x464DB3F4), MK_64(0x05613046,0xA01CF005), MK_64(0x7347EE0B,0xB09E8BCC), MK_64(0x5103A256,0x161A26FF), MK_64(0x8161EAC4,0x3A1176C2), MK_64(0xB9607373,0xCF92C2CC), MK_64(0xFDE8D4AD,0xD376300D) }; /* blkSize = 1024 bits. hashSize = 512 bits */ const u64b_t SKEIN1024_IV_512[] = { MK_64(0x8CF63BE5,0xE1EDF4B7), MK_64(0x256FD425,0xCBDE61EB), MK_64(0x497B412D,0xEBA3EF9D), MK_64(0x3CBD412A,0xD8293FBA), MK_64(0xD5AE34D6,0xF26F646E), MK_64(0x72879C01,0x0DA17B79), MK_64(0x61BD8F18,0x05AFF621), MK_64(0x75CB3C94,0x9CE0E463), MK_64(0xAF27329D,0x2CD71E37), MK_64(0x7DB5EC5E,0x1141CE9F), MK_64(0x76484C13,0x20CAB67B), MK_64(0x57EB52A6,0x561BE8C5), MK_64(0x51161125,0xE681412D), MK_64(0xF510D937,0x5439A9BC), MK_64(0xD18AF77C,0xFC425E3C), MK_64(0xEB05160C,0x3FEBB037) }; /* blkSize = 1024 bits. hashSize = 1024 bits */ const u64b_t SKEIN1024_IV_1024[] = { MK_64(0x5A4352BE,0x62092156), MK_64(0x5F6E8B1A,0x72F001CA), MK_64(0xFFCBFE9C,0xA1A2CE26), MK_64(0x6C23C396,0x67038BCA), MK_64(0x583A8BFC,0xCE34EB6C), MK_64(0x3FDBFB11,0xD4A46A3E), MK_64(0x3304ACFC,0xA8300998), MK_64(0xB2F6675F,0xA17F0FD2), MK_64(0x9D259973,0x0EF7AB6B), MK_64(0x0914A20D,0x3DFEA9E4), MK_64(0xCC1A9CAF,0xA494DBD3), MK_64(0x9828030D,0xA0A6388C), MK_64(0x0D339D5D,0xAADEE3DC), MK_64(0xFC46DE35,0xC4E2A086), MK_64(0x53D6E4F5,0x2E19A6D1), MK_64(0x5663952F,0x715D1DDD) }; #endif #endif /* _SKEIN_IV_H_ */ ekeyd-1.1.5/device/skein/brg_endian.h0000664000175000017500000001377511213205660015255 0ustar pmpm/* --------------------------------------------------------------------------- Copyright (c) 2003, Dr Brian Gladman, Worcester, UK. All rights reserved. LICENSE TERMS The free distribution and use of this software in both source and binary form is allowed (with or without changes) provided that: 1. distributions of this source code include the above copyright notice, this list of conditions and the following disclaimer; 2. distributions in binary form include the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other associated materials; 3. the copyright holder's name is not used to endorse products built using this software without specific written permission. ALTERNATIVELY, provided that this notice is retained in full, this product may be distributed under the terms of the GNU General Public License (GPL), in which case the provisions of the GPL apply INSTEAD OF those given above. DISCLAIMER This software is provided 'as is' with no explicit or implied warranties in respect of its properties, including, but not limited to, correctness and/or fitness for purpose. --------------------------------------------------------------------------- Issue 20/10/2006 */ #ifndef BRG_ENDIAN_H #define BRG_ENDIAN_H #define IS_BIG_ENDIAN 4321 /* byte 0 is most significant (mc68k) */ #define IS_LITTLE_ENDIAN 1234 /* byte 0 is least significant (i386) */ /* Include files where endian defines and byteswap functions may reside */ #if defined( __FreeBSD__ ) || defined( __OpenBSD__ ) || defined( __NetBSD__ ) # include #elif defined( BSD ) && ( BSD >= 199103 ) || defined( __APPLE__ ) || \ defined( __CYGWIN32__ ) || defined( __DJGPP__ ) || defined( __osf__ ) # include #elif defined( __linux__ ) || defined( __GNUC__ ) || defined( __GNU_LIBRARY__ ) # if !defined( __MINGW32__ ) && !defined(AVR) # include # if !defined( __BEOS__ ) # include # endif # endif #endif /* Now attempt to set the define for platform byte order using any */ /* of the four forms SYMBOL, _SYMBOL, __SYMBOL & __SYMBOL__, which */ /* seem to encompass most endian symbol definitions */ #if defined( BIG_ENDIAN ) && defined( LITTLE_ENDIAN ) # if defined( BYTE_ORDER ) && BYTE_ORDER == BIG_ENDIAN # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN # elif defined( BYTE_ORDER ) && BYTE_ORDER == LITTLE_ENDIAN # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN # endif #elif defined( BIG_ENDIAN ) # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN #elif defined( LITTLE_ENDIAN ) # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN #endif #if defined( _BIG_ENDIAN ) && defined( _LITTLE_ENDIAN ) # if defined( _BYTE_ORDER ) && _BYTE_ORDER == _BIG_ENDIAN # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN # elif defined( _BYTE_ORDER ) && _BYTE_ORDER == _LITTLE_ENDIAN # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN # endif #elif defined( _BIG_ENDIAN ) # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN #elif defined( _LITTLE_ENDIAN ) # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN #endif #if defined( __BIG_ENDIAN ) && defined( __LITTLE_ENDIAN ) # if defined( __BYTE_ORDER ) && __BYTE_ORDER == __BIG_ENDIAN # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN # elif defined( __BYTE_ORDER ) && __BYTE_ORDER == __LITTLE_ENDIAN # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN # endif #elif defined( __BIG_ENDIAN ) # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN #elif defined( __LITTLE_ENDIAN ) # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN #endif #if defined( __BIG_ENDIAN__ ) && defined( __LITTLE_ENDIAN__ ) # if defined( __BYTE_ORDER__ ) && __BYTE_ORDER__ == __BIG_ENDIAN__ # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN # elif defined( __BYTE_ORDER__ ) && __BYTE_ORDER__ == __LITTLE_ENDIAN__ # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN # endif #elif defined( __BIG_ENDIAN__ ) # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN #elif defined( __LITTLE_ENDIAN__ ) # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN #endif /* if the platform byte order could not be determined, then try to */ /* set this define using common machine defines */ #if !defined(PLATFORM_BYTE_ORDER) #if defined( __alpha__ ) || defined( __alpha ) || defined( i386 ) || \ defined( __i386__ ) || defined( _M_I86 ) || defined( _M_IX86 ) || \ defined( __OS2__ ) || defined( sun386 ) || defined( __TURBOC__ ) || \ defined( vax ) || defined( vms ) || defined( VMS ) || \ defined( __VMS ) || defined( _M_X64 ) || defined( AVR ) # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN #elif defined( AMIGA ) || defined( applec ) || defined( __AS400__ ) || \ defined( _CRAY ) || defined( __hppa ) || defined( __hp9000 ) || \ defined( ibm370 ) || defined( mc68000 ) || defined( m68k ) || \ defined( __MRC__ ) || defined( __MVS__ ) || defined( __MWERKS__ ) || \ defined( sparc ) || defined( __sparc) || defined( SYMANTEC_C ) || \ defined( __VOS__ ) || defined( __TIGCC__ ) || defined( __TANDEM ) || \ defined( THINK_C ) || defined( __VMCMS__ ) # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN #elif 0 /* **** EDIT HERE IF NECESSARY **** */ # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN #elif 0 /* **** EDIT HERE IF NECESSARY **** */ # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN #else # error Please edit lines 126 or 128 in brg_endian.h to set the platform byte order #endif #endif /* special handler for IA64, which may be either endianness (?) */ /* here we assume little-endian, but this may need to be changed */ #if defined(__ia64) || defined(__ia64__) || defined(_M_IA64) # define PLATFORM_MUST_ALIGN (1) #ifndef PLATFORM_BYTE_ORDER # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN #endif #endif #ifndef PLATFORM_MUST_ALIGN # define PLATFORM_MUST_ALIGN (0) #endif #endif /* ifndef BRG_ENDIAN_H */ ekeyd-1.1.5/device/skeinwrap.h0000664000175000017500000000273611230655740014061 0ustar pmpm/* skeinwrap.h * * Wrappers for standard skein operations for the eKey * * Copyright 2009 Simtec Electronics * * For licence terms refer to the COPYING file. */ #ifndef EKEY_SKEINWRAP_H #define EKEY_SKEINWRAP_H #include "skein/skein.h" typedef Skein_256_Ctxt_t EKeySkein; extern void PrepareSkein(EKeySkein *skein, const unsigned char *serial, const unsigned char *secret, const char *personalisation); /* 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456 */ #define EKEY_SKEIN_PERSONALISATION_LRS \ "20090609 support@simtec.co.uk EntropyKey/v1/LongTermReKeyingState " #define EKEY_SKEIN_PERSONALISATION_RS \ "20090609 support@simtec.co.uk EntropyKey/v1/ReKeyingState " #define EKEY_SKEIN_PERSONALISATION_PMS \ "20090609 support@simtec.co.uk EntropyKey/v1/MessageAuthenticationCodeState " #define EKEY_SKEIN_PERSONALISATION_EES \ "20090609 support@simtec.co.uk EntropyKey/v1/EntropyEncryptionState " #define EKEY_SKEIN_PERSONALISATION_LKMS \ "20090609 support@simtec.co.uk EntropyKey/v1/MessageAuthenticationCodeStateForLongTermReKeying " #endif /* EKEY_SKEINWRAP_H */ ekeyd-1.1.5/device/Makefile0000664000175000017500000000033611214433511013327 0ustar pmpmall: framer pemtest RM ?= rm -f framer: frames/frame.c skeinwrap.c frames/pem.c skein/skein.c skein/skein_block.c gcc -DFRAMER_TEST -o $@ $^ pemtest: frames/pem.c gcc -DTEST_PEM -o $@ $^ clean: $(RM) framer pemtest ekeyd-1.1.5/device/frames/0002775000175000017500000000000011672145156013161 5ustar pmpmekeyd-1.1.5/device/frames/frame.h0000664000175000017500000000377311230655740014427 0ustar pmpm/* frames/frame.h * * Framing information for eKey protocol * * Copyright 2009 Simtec Electronics * * For licence terms refer to the COPYING file. */ #ifndef EKEY_FRAMES_FRAME_H #define EKEY_FRAMES_FRAME_H /* * The following holds true for all frames * Frames start with a SOF of '* ' * Frames end with an EOF of '\r\n' * Frames have a frame type indicator which is two characters. * Frames have a PEM64 encoded 48 bit MAC (eight characters). * Frame payloads are always 48 bytes long. * Frames are always 64 bytes from start of SOF to end of EOF. * Thus, we have 2 + 2 + N + 8 + 2 => 64, so the payload * is always 50 characters. * */ /** * Prepare the framer's MAC skein * * @param sharedkey The shared secret (32 bytes) */ extern void framer_prepare_mac(const unsigned char *sharedkey); /** * Compute a MAC for a frame. * * @param frame The frame to compute the MAC for. Note, The SOF and * EOF are not considered to be part of the frame. * @param mactarget The location to write the computed pem64'd MAC to. * @note frame must point at the frame type (i.e. not the SOF) as the * MAC is computed on the frame type and payload only. */ extern void framer_compute_mac(const char *frame, char *mactarget); /** * Frame a payload into a frame packet. * * @param frame The frame to fill out. * @param ft1 The first character of the frame type, * @param ft2 The second character of the frame type, * @param payload The payload (must be 50 bytes). * * @note If payload is < 50 bytes but NULL terminated, then it will be * padded with ' '. * @note The caller is expected to fill out the SOF and EOF which will * not be read nor written by this routine, but which are expected * to be present by other routines. * @note \a frame should point at the SOF (or location there-for), this * routine will then fill out from frame[2] with \a ft1... */ extern void framer_fill_frame(char *frame, char ft1, char ft2, char *payload); #endif /* EKEY_FRAMES_FRAME_H */ ekeyd-1.1.5/device/frames/pem.c0000664000175000017500000001025511430012761014072 0ustar pmpm/* frames/pem.c * * PEM64 encoding for framing. * * Copyright 2009 Simtec Electronics * * For licence terms refer to the COPYING file. */ #include "pem.h" #ifdef TEST_PEM #include #include #include #include #endif static const char *dictionary = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static int inverse_dictionary[128] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0 -- 9 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 10 -- 19 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 20 -- 29 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 30 -- 39 */ -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, /* 40 -- 49 */ 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, /* 50 -- 59 */ -1, 0, -1, -1, -1, 0, 1, 2, 3, 4, /* 60 -- 69 */ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 70 -- 79 */ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, /* 80 -- 89 */ 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, /* 90 -- 99 */ 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, /* 100--109 */ 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, /* 110--119 */ 49, 50, 51, -1, -1, -1, -1, -1 }; /* 120--127 */ #define FILLERCHAR ('=') /* exported interface documented in pem.h */ int pem64_encode_bytes_length(int nbytes) { return ((nbytes + 2) / 3) * 4; } int pem64_encode_bytes(const unsigned char *inbytes, int nbytes, char *outtext) { int filledcount = 0; while (nbytes >= 3) { int c1 = inbytes[0], c2 = inbytes[1], c3 = inbytes[2]; *(outtext++) = dictionary[c1 >> 2]; *(outtext++) = dictionary[((c1 & 0x3) << 4) | (c2 >> 4)]; *(outtext++) = dictionary[((c2 & 0xf) << 2) | (c3 >> 6)]; *(outtext++) = dictionary[c3 & 0x3f]; filledcount += 4; nbytes -= 3; inbytes += 3; } if (nbytes == 2) { int c1 = inbytes[0], c2 = inbytes[1]; *(outtext++) = dictionary[c1 >> 2]; *(outtext++) = dictionary[((c1 & 0x3) << 4) | (c2 >> 4)]; *(outtext++) = dictionary[((c2 & 0xf) << 2)]; *(outtext++) = FILLERCHAR; filledcount += 4; } else if (nbytes == 1) { int c1 = inbytes[0]; *(outtext++) = dictionary[c1 >> 2]; *(outtext++) = dictionary[((c1 & 0x3) << 4)]; *(outtext++) = FILLERCHAR; *(outtext++) = FILLERCHAR; filledcount += 4; } return filledcount; } int pem64_decode_bytes(const char *intext, int nchars, unsigned char *outbytes) { unsigned char *outbcopy = outbytes; while (nchars >= 4) { int c1 = intext[0], c2 = intext[1], c3 = intext[2], c4 = intext[3]; int b1 = inverse_dictionary[c1], b2 = inverse_dictionary[c2], b3 = inverse_dictionary[c3], b4 = inverse_dictionary[c4]; if ((b1 == -1) || (b2 == -1) || (b3 == -1) || (b4 == -1)) return outbytes - outbcopy; *(outbytes++) = (b1 << 2) | (b2 >> 4); if (c3 != FILLERCHAR) *(outbytes++) = ((b2 & 0xf) << 4) | (b3 >> 2); if (c4 != FILLERCHAR) *(outbytes++) = ((b3 & 0x3) << 6) | b4; nchars -= 4; intext += 4; } return outbytes - outbcopy; } void pem64_encode_12bits(const short value, char *outtext) { *(outtext++) = dictionary[value & 0x3f]; *(outtext++) = dictionary[(value >> 6) & 0x3f]; } short pem64_decode_12bits(const char *intext) { int b1 = inverse_dictionary[(int) intext[0]], b2 = inverse_dictionary[(int) intext[1]]; if ((b1 == -1) || (b2 == -1)) return 0; return (b1 | (b2 << 6)); } #ifdef TEST_PEM static char pem_buffer[4096]; static void run_single_test(const unsigned char *buffer, const int buflen) { unsigned char *bcopy = calloc(buflen, 1); int pemchars = pem64_encode_bytes(buffer, buflen, pem_buffer); int pembytes = pem64_decode_bytes(pem_buffer, pemchars, bcopy); assert((pemchars % 4) == 0); assert(pembytes == buflen); assert(memcmp(bcopy, buffer, pembytes) == 0); free(bcopy); } #define R(S) run_single_test(S, sizeof(S) - 1) int main(int argc, char **argv) { R("123"); R("\1\2\3"); R("\1\2"); R("1234"); R("12345"); R("123456"); return 0; } #endif ekeyd-1.1.5/device/frames/pem.h0000664000175000017500000000343611302620664014107 0ustar pmpm/* frames/pem.h * * PEM64 encoding for framing. * * Copyright 2009 Simtec Electronics * * For licence terms refer to the COPYING file. */ #ifndef EKEY_FRAMES_PEM_H #define EKEY_FRAMES_PEM_H /* * PEM64 encoding takes bytes and encodes them into characters. * Each (up-to) three byte input produces four characters of output. * It is up to the caller to ensure buffers are the right sizes. */ /** * Encode some bytes in PEM64. * * @param inbytes The buffer to encode. * @param nbytes The number of bytes to encode. * @param outtext The buffer to fill. * @return The number of characters inserted into the output buffer. */ extern int pem64_encode_bytes(const unsigned char *inbytes, int nbytes, char *outtext); /** * Calculate resulting length of encoding bytes in PEM64. * * @param nbytes The number of bytes to encode. * @return The number of characters required to encode the output bytes. */ extern int pem64_encode_bytes_length(int nbytes); /** * Decode some text from PEM64. * * @param intext The buffer text to decode. * @param nchars The number of characters in the buffer. * @param outbytes The buffer to fill. * @return The number of bytes written into outbytes. */ extern int pem64_decode_bytes(const char *intext, int nchars, unsigned char *outbytes); /** Determine how many chars will be needed to encode N bytes */ #define PEM64_CHARS_NEEDED(nbytes) ((((nbytes) + 2) / 3) * 4) /** Determine how many bytes (may) be needed to decode N chars */ #define PEM64_BYTES_NEEDED(nchars) (((nchars) / 4) * 3) extern void pem64_encode_12bits(const short value, char *outtext); extern short pem64_decode_12bits(const char *intext); #endif /* EKEY_FRAMES_PEM_H */ ekeyd-1.1.5/device/frames/frame.c0000664000175000017500000000421211230655740014407 0ustar pmpm/* frames/frame.c * * Framing information for eKey protocol * * Copyright 2009 Simtec Electronics * * For licence terms refer to the COPYING file. */ #include "frame.h" #include "../skeinwrap.h" #include "pem.h" static EKeySkein framer_mac_base; static EKeySkein framer_mac; extern unsigned char *_serial_no; extern void *memcpy(void*,const void*,size_t); void framer_prepare_mac(const unsigned char *sharedkey) { PrepareSkein(&framer_mac_base, _serial_no, sharedkey, EKEY_SKEIN_PERSONALISATION_PMS); } void framer_compute_mac(const char *frame, char *mactarget) { unsigned char macbuf[32]; memcpy(&framer_mac, &framer_mac_base, sizeof(framer_mac)); Skein_256_Update(&framer_mac, frame, 52); Skein_256_Final_Pad(&framer_mac, macbuf); pem64_encode_bytes(macbuf, 3, mactarget); pem64_encode_bytes(macbuf + 29, 3, mactarget + 4); } void framer_fill_frame(char *frame, char ft1, char ft2, char *payload) { char *fr = frame + 2; int payload_left = 50; *fr++ = ft1; *fr++ = ft2; while ((payload_left > 0) && (*payload != 0)) { *fr++ = *payload++; payload_left--; } while (payload_left-- > 0) *fr++ = ' '; framer_compute_mac(frame + 2, fr); } #ifdef FRAMER_TEST unsigned char *_serial_no = "\x00\x01\x02\x03\x10\x11\x12\x13\xab\xac\xad\xae"; #include #include #include #include static unsigned char nullkey[32]; int main(int argc, char **argv) { char message[64]; char frame[64]; int counter = 0; int max = 50; frame[0] = '*'; frame[1] = ' '; frame[62] = '\r'; frame[63] = '\n'; memset(&(nullkey[0]), 0, 32); framer_prepare_mac(&(nullkey[0])); message[0] = message[1] = ' '; message[2 + pem64_encode_bytes(_serial_no, 12, &(message[2]))] = '\0'; framer_fill_frame(frame, 'S', '!', message); write(1, frame, 64); if (argc > 1) { if (atoi(argv[1]) > 0) max = atoi(argv[1]); } for (counter = 0; counter < max; ++counter) { snprintf(message, 64, "Frame number %d from pid %d (parent %d)", counter, getpid(), getppid()); framer_fill_frame(frame, 'I', '>', message); write(1, frame, 64); } return 0; } #endif ekeyd-1.1.5/udev/0002775000175000017500000000000011672145156011410 5ustar pmpmekeyd-1.1.5/udev/centos5/0002775000175000017500000000000011672145156012770 5ustar pmpmekeyd-1.1.5/udev/centos5/60-entropykey.rules0000664000175000017500000000234011557345404016475 0ustar pmpm# Entropy key udev rules # # Centos 5.5 rules for udev version 095 # # These rules create devices under /dev/entropykey/ # # CAUTION: There are known issues with the kernel ttyACM driver (cdc_acm). # Hard crashes have been observed with some kernel versions. # This ruleset has been tested on kernel version 2.6.18-238.9.1.el5 # which appears stable after several days testing. # # Copyright 2011 Simtec Electronics # # For licence terms refer to the COPYING file. # Detect an Entropy Key being inserted and add info values to environment ACTION=="add|change|remove", SUBSYSTEM=="tty", KERNEL=="ttyACM[0-9]*", BUS=="usb", SYSFS{idVendor}=="20df", SYSFS{idProduct}=="0001", IMPORT{program}="usb_id -nx %p" # Detect an Entropy Key being inserted and extract serial number ACTION=="add|change|remove", SUBSYSTEM=="tty", KERNEL=="ttyACM[0-9]*", BUS=="usb", SYSFS{idVendor}=="20df", SYSFS{idProduct}=="0001", IMPORT{program}="/lib/udev/entropykey_id.sh $env{ID_SERIAL}" # Add the /dev/entropykey/ symbolic link ENV{ENTROPY_KEY_SERIAL}!="", SYMLINK+="entropykey/$env{ENTROPY_KEY_SERIAL}" # And tell the ekeyd about the new device. ENV{ENTROPY_KEY_SERIAL}!="", RUN+="/lib/udev/entropykey.sh" ekeyd-1.1.5/udev/centos5/60-entropykey-uds.rules0000664000175000017500000000160611557345404017272 0ustar pmpm# Entropy key userspace driver udev rules # # Centos 5.5 rules for udev version 095 # # These rules create unix sockets under /var/run/entropykey/ # # CAUTION: There are known issues with the kernel ttyACM driver (cdc_acm) # in some Centos 5 kernels. To work round this issue a userspace # driver is provided (ekey-ulusbd) These udev rules enable # automatic detection of devices in that operation mode. # # Copyright 2011 Simtec Electronics # # For licence terms refer to the COPYING file. # Detect an Entropy Key being inserted and extract serial number ACTION=="add|change|remove", SUBSYSTEM=="usb", BUS=="usb", SYSFS{idVendor}=="20df", SYSFS{idProduct}=="0001", IMPORT{program}="/lib/udev/entropykey_id.sh $sysfs{serial} %b $sysfs{devnum}" # And tell the ekeyd about the device action. ENV{ENTROPY_KEY_SERIAL}!="", RUN+="/lib/udev/entropykey.sh" ekeyd-1.1.5/udev/centos5/entropykey_id.sh0000775000175000017500000000100211557253423016202 0ustar pmpm#!/bin/sh # # Helper for entropy key udev rules to reformat values # # entropykey_id.sh # convert ID_SERIAL to ID_SERIAL_SHORT ID_SERIAL_SHORT=$(echo ${1} | tr / . | awk -F_ '{print $NF}' ) echo "ENTROPY_KEY_SERIAL=${ID_SERIAL_SHORT}" # convert busnum if [ "x${2}" != "x" ]; then BUSNUM=$(echo ${2} | awk -F- '{printf("%03d", $1)}') echo "BUSNUM=${BUSNUM}" fi # device number if [ "x${3}" != "x" ]; then DEVNUM=$(echo ${3} | awk '{printf("%03d", $1)}') echo "DEVNUM=${DEVNUM}" fi ekeyd-1.1.5/udev/centos6/0002775000175000017500000000000011672145156012771 5ustar pmpmekeyd-1.1.5/udev/centos6/60-entropykey.rules0000664000175000017500000000174111562735614016504 0ustar pmpm# Entropy key udev rules # # Centos/RHEL 6 rules for udev version 147 # # These rules create devices under /dev/entropykey/ # # Copyright 2011 Simtec Electronics # # For licence terms refer to the COPYING file distributed with the source. # Detect an Entropy Key being inserted and add info values to environment ACTION=="add|change|remove", SUBSYSTEM=="tty", KERNEL=="ttyACM[0-9]*", BUS=="usb", ATTRS{idVendor}=="20df", ATTRS{idProduct}=="0001", IMPORT{program}="usb_id --export %p" # Detect an Entropy Key being inserted and extract serial number ACTION=="add|change|remove", SUBSYSTEM=="tty", KERNEL=="ttyACM[0-9]*", ATTRS{idVendor}=="20df", ATTRS{idProduct}=="0001", IMPORT{program}="/bin/echo ENTROPY_KEY_SERIAL=$env{ID_SERIAL_SHORT}" # Add the /dev/entropykey/ symbolic link ENV{ENTROPY_KEY_SERIAL}!="", SYMLINK+="entropykey/$env{ENTROPY_KEY_SERIAL}" # And tell the ekeyd about the new device. ENV{ENTROPY_KEY_SERIAL}!="", RUN+="/lib/udev/entropykey.sh" ekeyd-1.1.5/udev/centos6/60-entropykey-uds.rules0000664000175000017500000000112411562735614017270 0ustar pmpm# Entropy key userspace driver udev rules # # RHEL/Centos 6 rules for udev version 147 # # These rules create unix sockets under /var/run/entropykey/ # # Copyright 2011 Simtec Electronics # # For licence terms refer to the COPYING file. # Detect an Entropy Key being inserted and extract serial number ACTION=="add|change|remove", SUBSYSTEM=="usb", BUS=="usb", ATTRS{idVendor}=="20df", ATTRS{idProduct}=="0001", IMPORT{program}="/bin/echo ENTROPY_KEY_SERIAL=$attr{serial}" # And tell the ekeyd about the device action. ENV{ENTROPY_KEY_SERIAL}!="", RUN+="/lib/udev/entropykey.sh" ekeyd-1.1.5/udev/debian/0002775000175000017500000000000011672145156012632 5ustar pmpmekeyd-1.1.5/udev/debian/60-UDEKEY01.rules0000664000175000017500000000150011556774316015261 0ustar pmpm# Simtec Electronics UDEKEY01 Rules for udev # Detect an Entropy Key being inserted ACTION=="add|change", SUBSYSTEM=="tty", KERNEL=="ttyACM[0-9]*", ATTRS{idVendor}=="20df", ATTRS{idProduct}=="0001", IMPORT{program}="usb_id --export %p" ACTION=="add|change", SUBSYSTEM=="tty", KERNEL=="ttyACM[0-9]*", ATTRS{idVendor}=="20df", ATTRS{idProduct}=="0001", IMPORT{program}="/bin/echo ENTROPY_KEY_SERIAL=$env{ID_SERIAL_SHORT}" # Add the /dev/entropykey/FOO symbolic link ACTION=="add|change", ENV{ENTROPY_KEY_SERIAL}!="", SYMLINK+="entropykey/$env{ENTROPY_KEY_SERIAL}" # And tell the ekeyd about the new device. ACTION=="add|change", ENV{ENTROPY_KEY_SERIAL}!="", RUN+="/lib/udev/entropykey.sh" # And remove the entropy key from the daemon on device removal ACTION=="remove", ENV{ENTROPY_KEY_SERIAL}!="", RUN+="/lib/udev/entropykey.sh" ekeyd-1.1.5/udev/debian/60-UDEKEY01-UDS.rules0000664000175000017500000000133311556774316015716 0ustar pmpm# Simtec Electronics UDEKEY01 Rules for udev # Alternative UDEV rules for the unix-domain-socket mode instead of relying on cdc-acm # Detect an Entropy Key being inserted # ACTION=="add", SUBSYSTEM=="usb", DEVTYPE=="usb_device", ATTRS{idVendor}=="20df", ATTRS{idProduct}=="0001", IMPORT{program}="usb_id --export %p" ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="20df", ATTRS{idProduct}=="0001", IMPORT{program}="/bin/echo ENTROPY_KEY_SERIAL=$attr{serial}" # And tell the ekeyd about the new device. ACTION=="add|change", ENV{ENTROPY_KEY_SERIAL}!="", RUN+="/lib/udev/entropykey.sh" # And remove the entropy key from the daemon on device removal ACTION=="remove", ENV{ENTROPY_KEY_SERIAL}!="", RUN+="/lib/udev/entropykey.sh" ekeyd-1.1.5/udev/entropykey.sh0000775000175000017500000000311611613247672014160 0ustar pmpm#!/bin/sh # # Entropy key udev helper, ensures ekeyd is updated with new devices # # Copyright 2009-2011 Simtec Electronics # # For licence terms refer to the COPYING file. BINPATH=/usr/sbin # This function waits for the USB dev nodes to be made before # attempting to allow the ULUSBD to attach, this might resolve # a race condition where udev runs us before the nodes are # available. wait_for_usb () { COUNTER=0 while ! test -e /dev/bus/usb/${BUSNUM}/${DEVNUM}; do sleep 1 COUNTER=$(( ${COUNTER} + 1 )) test ${COUNTER} -ge 10 && exit 1 done $BINPATH/ekey-ulusbd -b${BUSNUM} -d${DEVNUM} -P/var/run/ekey-ulusbd-${ENTROPY_KEY_SERIAL}.pid -p/var/run/entropykeys/${ENTROPY_KEY_SERIAL} -D sleep 1 $BINPATH/ekeydctl ${ACTION} /var/run/entropykeys/${ENTROPY_KEY_SERIAL} exit 0 } if test "x$SUBSYSTEM" = "xtty"; then # Update ekeyd with device operation $BINPATH/ekeydctl ${ACTION} /dev/entropykey/${ENTROPY_KEY_SERIAL} else if test "x$ACTION" = "xadd"; then # start userland USB connection daemon if test "x${BUSNUM}" = "x" -o "x${DEVNUM}" = "x"; then exit 0 fi if test -r "/var/run/ekey-ulusbd-${ENTROPY_KEY_SERIAL}.pid"; then kill $(cat "/var/run/ekey-ulusbd-${ENTROPY_KEY_SERIAL}.pid") || true fi mkdir -p /var/run/entropykeys wait_for_usb & exit 0 fi # Update ekeyd with device operation $BINPATH/ekeydctl ${ACTION} /var/run/entropykeys/${ENTROPY_KEY_SERIAL} if test "x$ACTION" = "xremove"; then rm "/var/run/ekey-ulusbd-${ENTROPYKEY_KEY_SERIAL}.pid" rm "/var/run/entropykeys/${ENTROPYKEY_KEY_SERIAL}" fi fi exit 0 ekeyd-1.1.5/udev/ekeyd-ulusbd.blacklist0000664000175000017500000000013211612044005015652 0ustar pmpm# The CDC ACM driver on this OS is buggy and can cause system crashes. blacklist cdc_acm ekeyd-1.1.5/udev/fedora14/0002775000175000017500000000000011672145156013015 5ustar pmpmekeyd-1.1.5/udev/fedora14/60-entropykey.rules0000664000175000017500000000174111562735614016530 0ustar pmpm# Entropy key udev rules # # Centos/RHEL 6 rules for udev version 147 # # These rules create devices under /dev/entropykey/ # # Copyright 2011 Simtec Electronics # # For licence terms refer to the COPYING file distributed with the source. # Detect an Entropy Key being inserted and add info values to environment ACTION=="add|change|remove", SUBSYSTEM=="tty", KERNEL=="ttyACM[0-9]*", BUS=="usb", ATTRS{idVendor}=="20df", ATTRS{idProduct}=="0001", IMPORT{program}="usb_id --export %p" # Detect an Entropy Key being inserted and extract serial number ACTION=="add|change|remove", SUBSYSTEM=="tty", KERNEL=="ttyACM[0-9]*", ATTRS{idVendor}=="20df", ATTRS{idProduct}=="0001", IMPORT{program}="/bin/echo ENTROPY_KEY_SERIAL=$env{ID_SERIAL_SHORT}" # Add the /dev/entropykey/ symbolic link ENV{ENTROPY_KEY_SERIAL}!="", SYMLINK+="entropykey/$env{ENTROPY_KEY_SERIAL}" # And tell the ekeyd about the new device. ENV{ENTROPY_KEY_SERIAL}!="", RUN+="/lib/udev/entropykey.sh" ekeyd-1.1.5/udev/fedora14/60-entropykey-uds.rules0000664000175000017500000000112411562735614017314 0ustar pmpm# Entropy key userspace driver udev rules # # RHEL/Centos 6 rules for udev version 147 # # These rules create unix sockets under /var/run/entropykey/ # # Copyright 2011 Simtec Electronics # # For licence terms refer to the COPYING file. # Detect an Entropy Key being inserted and extract serial number ACTION=="add|change|remove", SUBSYSTEM=="usb", BUS=="usb", ATTRS{idVendor}=="20df", ATTRS{idProduct}=="0001", IMPORT{program}="/bin/echo ENTROPY_KEY_SERIAL=$attr{serial}" # And tell the ekeyd about the device action. ENV{ENTROPY_KEY_SERIAL}!="", RUN+="/lib/udev/entropykey.sh" ekeyd-1.1.5/udev/fedora15/0002775000175000017500000000000011672145156013016 5ustar pmpmekeyd-1.1.5/udev/fedora15/60-entropykey.rules0000664000175000017500000000174111562735614016531 0ustar pmpm# Entropy key udev rules # # Centos/RHEL 6 rules for udev version 147 # # These rules create devices under /dev/entropykey/ # # Copyright 2011 Simtec Electronics # # For licence terms refer to the COPYING file distributed with the source. # Detect an Entropy Key being inserted and add info values to environment ACTION=="add|change|remove", SUBSYSTEM=="tty", KERNEL=="ttyACM[0-9]*", BUS=="usb", ATTRS{idVendor}=="20df", ATTRS{idProduct}=="0001", IMPORT{program}="usb_id --export %p" # Detect an Entropy Key being inserted and extract serial number ACTION=="add|change|remove", SUBSYSTEM=="tty", KERNEL=="ttyACM[0-9]*", ATTRS{idVendor}=="20df", ATTRS{idProduct}=="0001", IMPORT{program}="/bin/echo ENTROPY_KEY_SERIAL=$env{ID_SERIAL_SHORT}" # Add the /dev/entropykey/ symbolic link ENV{ENTROPY_KEY_SERIAL}!="", SYMLINK+="entropykey/$env{ENTROPY_KEY_SERIAL}" # And tell the ekeyd about the new device. ENV{ENTROPY_KEY_SERIAL}!="", RUN+="/lib/udev/entropykey.sh" ekeyd-1.1.5/udev/fedora15/60-entropykey-uds.rules0000664000175000017500000000112411562735614017315 0ustar pmpm# Entropy key userspace driver udev rules # # RHEL/Centos 6 rules for udev version 147 # # These rules create unix sockets under /var/run/entropykey/ # # Copyright 2011 Simtec Electronics # # For licence terms refer to the COPYING file. # Detect an Entropy Key being inserted and extract serial number ACTION=="add|change|remove", SUBSYSTEM=="usb", BUS=="usb", ATTRS{idVendor}=="20df", ATTRS{idProduct}=="0001", IMPORT{program}="/bin/echo ENTROPY_KEY_SERIAL=$attr{serial}" # And tell the ekeyd about the device action. ENV{ENTROPY_KEY_SERIAL}!="", RUN+="/lib/udev/entropykey.sh" ekeyd-1.1.5/doc/0002775000175000017500000000000011672145156011212 5ustar pmpmekeyd-1.1.5/doc/README.security0000664000175000017500000002255011556361136013741 0ustar pmpmEntropy Key =========== This document explains the process by which the Entropy Key gathers entropy and ensures that it is as close to one Shannon per bit as it can. The document also covers the keys contained in the Entropy Key device, and how they are used to secure communication between the device and the host. How the Entropy Key gathers its data ------------------------------------ The Entropy Key uses P-N semiconductor junctions reverse biassed with a high enough voltage to bring them near to, but not beyond, breakdown in order to generate noise. In other words, it has a pair of devices that are wired up in such a way that as a high potential is applied across them, where electrons do not normally flow in this direction and would be blocked, the high voltage compresses the semiconduction gap sufficiently that the occasional stray electron will quantum tunnel through the P-N junction. (This is sometimes referred to as avalanche noise.) When this happens is unpredictable, and the occurrence of these events is what the Entropy Key measures. These noise generators are then coupled to a 72MHz ARM Cortex-M3 CPU on the device. This processor samples the generators at a high frequency, forming a stream of random bytes. These streams of bytes are then analysed using Üli Maurer's universal test for random bit generators whereby the amount of entropy in the streams is estimated rather conservatively. The streams are also exclusive-ORed together and that stream's entropy is estimated in the same manner. If the raw streams appear to have severely reduced entropy then it indicates a fault in that generator, if the third stream has low entropy then it indicates that the generators have correlated and are not independently gathering entropy. Any of those three states are considered a failure mode and will result in the eKey locking itself out of the host, returning only an error code instead of generating entropy packets. The two raw streams are then processed further in a debiassing process invented by John von Neumann. Their entropy is estimated after the debiassing process has been performed. Again, if the estimated entropy in the streams is seen to vary too wildly at this stage, the Entropy Key will lock itself out. The processed streams are then mixed into a pool made with a secure hashing function. Once at least 50% more (estimated) entropy has been mixed into the pool than it could possibly hold it is finalised and another pool initialised. Once enough pools have been processed to fill 20000 bits, the totality is subjected to the tests stipulated in FIPS 140-2. These tests produce a PASS/FAIL indicator for the block. On its own, this is not useful, since a perfectly random block could quite plausibly fail the tests. The Entropy Key therefore keeps running statistics on the FIPS 140-2 tests and will lock itself out if the ratio of failed blocks to passed blocks rises above a conservative estimate of the statistical likelyhood of failure. Once the block has been analysed, regardless of its PASS/FAIL indication, it is chopped up into 32 byte packets and these are handed off to the protocol handler in the device. Through this process therefore, each 256 bit block of data handed to the host was formed from somewhere in the region of between 3000 and 5000 bits read from the generators. How the communication between the device and host is secured ------------------------------------------------------------ While the host communicates to the device via a severely reduced streaming protocol, the device communicates to the host in quite sophisticated packets of data in a byte stream. For more information about the minutae of the protocol, please see README.protocol. When talking about the security measures of the Entropy Key device, we need to consider that a running device is aware of three symmetric cryptography keys. These keys form a heirarchy descending from the Master Key which comes printed on a piece of card in a security envelope. Key name | Creation | Used for ---------------+------------------+--------------------------------------- Master Key | Manufacture time | Creating Long-Term keys Long-Term Key | ekey-rekey tool | Creating session keys Session Key | ekeyd | Securing communications from device. The Master Key (MK) is created when the device is manufactured and cannot be changed. The only copy of the Master Key is on the card which comes with the Entropy Key device. The manufacturer does not keep a copy of this key; it is printed out as the key is generated, and then forgotten. The Long-Term Key (LTK) can be changed by using the ekey-rekey (or ekey-setkey) tools provided as part of the host software. These tools allow you to change the Long-Term key whenever you wish, although you need to have the Master Key to hand in order to do this. A new Session Key (SK) is created regularly (approximately once every 45-60s) and is used to secure the communications from the device to the host as explained below. Each packet from the device to the host is authenticated with a MAC. This is a 48 bit value calculated by hashing the content of the packet along with the current session key, the serial number of the device and a Skein personalisation string for this purpose. This allows the device to trust that packets coming from the device are valid and have not been tampered with, nor accidentally corrupted by the host. In order to create a new SK, the host must know the LTK and perform the following re-keying process: 1. The host creates a nonce of between zero and 4095 bytes. Typically this will be around 12 byte and will contain a monotonic counter as well as some amount of random data derived from a random pool. 2. The host PEM encodes the nonce and sends to the device a packet consisting of a 'K', the PEM encoded nonce, and a '.' 3. The device responds with a K! packet containing 32 bytes of entropy gathered and mixed in the same way as entropy which would normally be passed to the host. 4. The host verifies that K! packet states the number of bytes which it believes it sent as the nonce. 5. Both host and device, independently, hash together the serial number of the key, the host's nonce, the device's nonce, the LK and a Skein personalisation string for this purpose. The finalised hash value is then used as the SK going forward. Typically, assuming the Entropy Key has not detected an attack or failure mode, the device will then start sending E! (entropy) packets to the host as detailed below. When the host wishes to create a new LK, the process is as above except that in addition, the steps below happen: 1.1. The host hashes the nonce it has created, with the MK and a Skein personalisation for this purpose. 1.2. The host PEM encodes the first 24 and last 24 bits of this hash and sends to the device a packet consisting of 'M' and the eight characters of PEM encoded hash. 1.3 The device responds with an M> packet indicating that LK rekeying is now permitted. In step 2, the host sends an 'L' instead of a 'K' to indicate it wishes to rekey the LK. In steps 3 and 4, the packet from the device is an L! instead of a K!. However, there is also: 2.5. The device hashes the nonce sent by the host in the same way as the host did in 1.1. If the hash does not match that sent by the host in 1.2 then the device responds with an 'l>' packet to indicate failure. In step 5, the personalisation used is one specific to the process of LK rekeying and once the new LK has been calculated, the device commits it to non-volatile storage inside the CPU. How Entropy Packets are secured ------------------------------- Each E! packet carries a sequence number in its extra-information field. That sequence number, along with the session key, the serial number of the device and a Skein personalisation string for this purpose are hashed together to form a 256 bit one-time-pad. The entropy to be sent from device to host is then exclusive-ored (XOR) with this one-time-pad before being PEM encoded and sent as a packet. Once the sequence number reaches 4095 the device stops sending E! packets until a new SK is negotiated. Frequency of packets -------------------- The most common packet sent by the device is the E! packet. Each time a 20000 bit state is completed, (and the device has an SK which hasn't expired) 78 E! packets will be queued for transmission. This happens slightly more often than once per second, which leads to approximately 86 E! packets per second. Each one carries a 12 bit sequence number and a 48 bit MAC. This leads us to assume that once every 2^59 packets one will have gathered enough data to perform an attack by substituting an E! packet for one which has gone before, which matches MAC and sequence number. This is therefore roughly every 212000 millennia. Fortunately even were the sequence number and MAC to collide with a packet already seen, the session key is exceedingly unlikely to actually be the same. As such, despite being able to substitute an E! packet into the stream, the entropy which is decrypted will not be predictable by the attacker. The greatest frequency by which rekeying events can be forced and thus potentially leak information about the keys in the device is limited directly by how fast the device can gather entropy. Therefore devices are hard-limited to approximately 86 rekeyings per second. ekeyd-1.1.5/doc/README.FreeBSD0000664000175000017500000001161711556361136013306 0ustar pmpmEntropy Key - FreeBSD ===================== Overview -------- Although FreeBSD is not a directly supported Operating System there have been numerous reports of success compiling and using the Entropy Key tools from source. The main issues appear to be getting the kernel USB tty driver to recognise the Entropy key. Ekey source changes ------------------- FreeBSD 8.0-RELEASE ------------------- Rob Neal notes that on 8.0 No source changes were required to the kernel to get teh Entropy Key USB tty device to appear. The options 'device ucom' and 'device umodem' were needed in the kernel because they are not in GENERIC. FreeBSD 7.1-STABLE ------------------ Rob Neal has kindly provided the following notes to get the Entropy Key working on this release. --- /usr/src/sys/dev/usb/old.umodem.c 2010-01-25 20:40:59.000000000 -0700 +++ /usr/src/sys/dev/usb/umodem.c 2010-01-25 21:10:34.000000000 -0700 @@ -127,6 +127,7 @@ { USB_VENDOR_KYOCERA, USB_PRODUCT_KYOCERA_AHK3001V, 0 }, { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5720, 0 }, { USB_VENDOR_CURITEL, USB_PRODUCT_CURITEL_PC5740, 0 }, + { USB_VENDOR_SIMTEC, USB_PRODUCT_SIMTEC_EKEY, 0 }, { 0, 0, 0 }, }; @@ -249,6 +250,9 @@ umodem_products[i].product == UGETW(dd->idProduct) && umodem_products[i].interface == id->bInterfaceNumber) { ret = UMATCH_VENDOR_PRODUCT; + if ((UGETW(dd->idVendor) == USB_VENDOR_SIMTEC) && + (UGETW(dd->idProduct) == USB_PRODUCT_SIMTEC_EKEY)) + return(UMATCH_VENDOR_PRODUCT); break; } } Driver: /usr/src/sys/dev/usb/usbdevs Add Simtec vendor id and product id entries in the appropriate alphabetical locations: vendor SIMTEC 0x20df Simtec Electronics /* Simtec Electronics */ product SIMTEC EKEY 0x0001 Ekey Entropy Device /usr/src/sys/dev/usb/umodem.c see diffs in umodem.diff. Modify to recognize the Simtec vendor id and product id, and ignore the missing bulk data in. Which was erratic on my box, sometimes it found it, sometimes not. The ucom driver is also required, if not already present. Loading the umodem driver will result in /dev/cuaUx and /dev/ttyUx entries being created. Use the /dev/cuaUx entry to represent the key. /dev/ttyUx barked loudly, cblock issue. /etc/devd.conf: attach 100 { /* 100 or whatever priority rank you like */ match "vendor" "0x20df"; match "product" "0x0001"; action "logger Ekey $sernum vendor $vendor product $product"; action "ln -fs /dev/cuaU0 /var/run/entropykeys/M.9rBjBLNzFWQCFD"; // note: $device-name (ucom0 in this case) could be parsed to // auto-construct the /dev/cuaUx entry. I'm lazy. action "/usr/sbin/ekeyd"; }; detach 100 { match "vendor" "0x20df"; match "product" "0x0001"; action "ekeydctl stats $sernum | logger"; action "ekeydctl shutdown"; action "logger Ekey $sernum removed from system"; }; /ekey/src/daemon/Makefile LUA include location is wrong: LUA_INC ?= -I/usr/local/include/lua5.1 /ekey/src/daemon/crc8.h add typedef int ssize_t; before the crc8() definition /etc/entropykeys/xxx careful, they get whacked by gmake install. use gmake instead of make. /etc/entropykey/ekeyd.conf lua and luasockets are needed for the ulusbd, but AF_UNIX support isn't part of the package, so things fall down. Use TCPControlSocket, comment out the UnixControlSocket ulusbd refused to find the usb device, but usbdev was happy: root@bulldog~: usbdevs -v Controller /dev/usb0: addr 1: full speed, self powered, config 1, UHCI root hub(0x0000), Intel(0x0000) , rev 1.00 port 1 addr 2: full speed, power 76 mA, config 1, Entropy Key(0x0001), Simtec E lectronics(0x20df), rev 2.00 port 2 addr 3: full speed, power 98 mA, config 1, Geek Squad(0x0031), Geek Squa d(0x154b), rev 1.00 root@bulldog~: ekey-ulusbd -b0 -d2 -p/dev Scanning for USB device 0/2 MRN bus->/dev/usb0<-found Error locating Simtec Entropy Key at 0/2 root@bulldog~: ekey-ulusbd -b0 -d1 -p/dev Scanning for USB device 0/1 MRN bus->/dev/usb0<-found Error locating Simtec Entropy Key at 0/1 root@bulldog~: ekey-ulusbd -b0 -d3 -p/dev Scanning for USB device 0/3 MRN bus->/dev/usb0<-found Error locating Simtec Entropy Key at 0/3 I hacked in a fprintf to display what bus it thought it was finding. but things are fine in ekeyville: root@bulldog~: ekeydctl list NR,OK,Status,Path,SerialNo 1,YES,Running OK,/var/run/entropykeys/M.9rBjBLNzFWQCFD,M/9rBjBLNzFWQCFD root@bulldog~: ekeydctl stats $SER BytesRead=11532416 BytesWritten=794 ConnectionNonces=44 ConnectionPackets=180194 ConnectionRekeys=44 ConnectionResets=2 ConnectionTime=1432 EntropyRate=32128 FipsFrameRate=1.61 FrameByteLast=11532352 FramesOk=180194 FramingErrors=0 KeyDbsdShannonPerByteL=2.91 KeyDbsdShannonPerByteR=3.03 KeyRawShannonPerByteL=2.84 KeyRawShannonPerByteR=2.86 KeyRawShannonPerByteX=2.83 KeyTemperatureC=31.75 KeyTemperatureF=89.15 KeyTemperatureK=304.9 KeyVoltage=3.302 PacketErrors=1 PacketOK=180193 ReadRate=64426 TotalEntropy=5750912 WriteRate=4 ekeyd-1.1.5/doc/README.egd-linux0000664000175000017500000000604411556361136013766 0ustar pmpmEntropy Key - EGD -> Linux Daemon ================================= In today's world of virtualised and "cloud" computing, entropy becomes more and more difficult to get to the virtual hosts which need it the most. With advancements in attack techniques; along with the associated security enhancements inherent in operating systems; the need for more entropy on even the simplest of hosts is increased. Modern GNU/Linux distributions typically consume 64 bits of random data on every process-start. If a webserver is using CGIs and those CGIs could be considered attack vectors against the host, then it is of important that the random data used to secure the process is of the highest quality. The Entropy Key daemon (ekeyd) can present entropy on TCP sockets using a protocol originally written for the 'Entropy Gathering Daemon' (EGD) which has become somewhat of an unofficial standard. The egd-linux daemon provided with the Entropy Key software allows any host to connect to the ekeyd and request entropy which it can then use to re-stock its local random pool. Since this is possible from any host which can establish a TCP stream to the ekeyd's listening socket, this can be used to provide entropy to virtual hosts. To use the egd-linux daemon to acquire entropy from an ekeyd instance, first the ekeyd must be configured to provide the EGD interface. To do this, disable any other output mode (e.g. SetOutputToKernel()) and create an EGDTCPSocket which is accessible externally. e.g. EGDTCPSocket(8888, "0.0.0.0") to bind to port 8888 on all interfaces. Then restart the ekeyd and verify with ekeydctl that all the Entropy Key devices have been added to the daemon properly. Each host which will run egd-linux will first need its random pool configuring so that its "low watermark" is high enough that it will trip egd-linux into filling it up. Typically hosts which have insufficient incoming entropy will sit around 180 bits of entropy in the pool. We would recommend that you set the low watermark to 1024 bits, to ensure there is always a good slush of bits available if the ekeyd is too busy to service the demand immediately. To configure this, run: sysctl kernel.random.write_wakeup_threshold=1024 as root. Next, start the egd-linux daemon on the host running ekeyd. The easiest way to do this is simply: egd-linux -D/var/run/egd-linux.pid This will start egd-linux, it will attempt to connect to localhost on port 8888, and then feed entropy from the ekeyd to the kernel pool. If there is at least 1024 bits in the pool then egd-linux will wait, consuming no entropy from the ekeyd. This behaviour lends itself to multiple egd-linux instances talking to a single ekeyd. Indeed a single Entropy Key can supply enough entropy to keep a small network of desktop computers and a small office server fully stocked. Each other host (virtual or otherwise) which requires entropy will need to be told where the ekeyd can be found: egd-linux -H10.19.3.101 -D/var/run/egd-linux.pid If you run egd-linux with the '-h' argument then it will display usage information. ekeyd-1.1.5/doc/README.egd-protocol0000664000175000017500000000355511556361136014474 0ustar pmpmEntropy Key - EGD Protocol ========================== The EGD (Entropy Gathering Daemon) program defined a simple byte-based protocol for retrieving entropy from a daemon. The protocol is run over stream sockets, either UNIX domain sockets, or TCP sockets. The Entropy Key software can provide sockets which act in the same way in order to allow software compatible with EGD to retrieve high quality entropy from the Entropy Keys. The protocol is a byte-based command/response protocol which is always initiated by the client. Where values longer than one byte are used, they are in network-byte-order. i.e. U32 is an unsigned four byte number, big-endian. Command: 0x00 - Read entropy pool size Arguments: None Response: U32 (Available entropy in bits) Command: 0x01 - Retrieve entropy (non-blocking) Arguments: U8 (Number of bytes of entropy desired) Response: U8 (Number of bytes of entropy returned) STR (The bytes of entropy) Command: 0x02 - Retrieve entropy (blocking) Arguments: U8 (Number of bytes of entropy desired) Reponse: STR (The bytes of entropy) This command will block until sufficient entropy is available to satisfy the request. The entropy will be streamed to the client as and when it becomes available. The ekeyd will make some attempt to spread the available entropy around between clients which are blocked, however a blocking client can starve a non-blocking client of entropy. Command: 0x03 - Add entropy to pool Arguments: U16 (Number of shannons of entropy) U8 (Number of bytes containing that) STR (The bytes of entropy) Response: None This command is parsed by ekeyd but ignored. Command: 0x04 - Get PID of EGD Arguments: None Response: U8 (Number of bytes in PID string) STR (PID string) This command is parsed by ekeyd but will always return PID -1. ekeyd-1.1.5/doc/README.Centos50000664000175000017500000000344011562735614013412 0ustar pmpmEntropy Key - Centos 5 Operating system notes ============================================= The following is the Centos 5/RHEL 5 usage notes for the Entropy Key. Centos 5.0 - 5.4 ---------------- Please be aware of the issues outline below and verify operation in your specific use case. The cdc_acm kernel driver module in earlier CentOS 5 (version 2.6.18-128.el5 reported) has been reported to have significant issues. Symptoms include complete system lockups requiring a reset to continue. On these systems we advise the use of the userspace USB driver to communicate with the entropy key. The ekeyd-ulusbd package when installed provides the udev rules to facilitate this method of operation. Please ensure the cdc_acm driver is blacklisted as appropriate for your configuration. CentOS 5.5 - 5.6 ---------------- Centos 5.5 and 5.6 shipped with a kernel version (version 2.6.18-194.el5 and 2.6.18-238.el5 respectively) where the CDC ACM driver appears to operate correctly with the standard tty based interface. Centos 5.5 users should only install the ekeyd-ulusbd package for the userspace driver if they experience actual problems in their specific configuration. The kernel cdc_acm driver must be manually disabled for this mode of operation to work correctly. Dynamic udev based insertion and removal of the entropy key works correctly. Please ensure the software is installed *before* inserting the entropy key or the udev based autodetection will not operate and the ekeyd daemon will not automatically add the key. This can be corrected simply by issuing "rmmod cdc_acm;modprobe cdc_acm" once the software package is installed. The installation will not automatically start the entropy key daemon after installation, it can be started in the usual way by running "/etc/init.d/ekeyd start" as root. ekeyd-1.1.5/doc/README0000664000175000017500000001022511613247233012062 0ustar pmpmEntropy Key - Quick Start ========================= For more specific information, please see: README.protocol - Information regarding the Entropy Key protocol README.security - Information regarding security and the Entropy Key README.egd-linux - Information regarding the ekey-egd-linux tool README.egd-protocol - Information regarding the EGD protocol Quick Start ----------- 1) Install the package. This will provide the ekeyd daemon, the ekey-rekey tool and the ekeydctl tool. By default, the daemon will not start immediately. 2) Plug the Entropy Key into a spare USB port. Assuming the operating system has appropriate device drivers for standard CDC serial ports, a device node for the character device should be available. On Linux systems where the appropriate udev rules have been installed, a symbolic link to the device in /dev/entropykey/ will be created. The key will automatically be added to the running daemon. 3) Use the ekey-rekey tool to generate a new long term key. The device's USB serial number and master key are required to perform this operation. The resulting long term key is stored in the daemon's keyring file and should only be accessible by trusted users. The serial number and new long-term-key are also printed to the console as an indication that the keying process was completed succesfully. The device's USB serial number is printed on a label attached to the documentation for your Entropy Key and is also available as the USB device serial number in tools such as lsusb. The master key is also obtained from the accompanying printed material. The master key is irreplaceable and if lost the device can never be re-keyed again. ******************************************************** * Please ensure the master key is kept somewhere safe! * * The manufacturer does not keep duplicate information * ******************************************************** 4) The /etc/entropykey/ekeyd.conf configuration file may be edited. A system administrator may have specific requirements, any alterable parameters can be set in the daemon configuration file. 5) The ekeyd daemon should be started. The daemon will communicate with the Entropy Key and output the decrypted entropy using the configured output method. 6) The status of the Entropy Key may be checked. The ekeydctl program may be used, with the 'list' command , to verify the new key is operating correctly and is properly configured. A correctly operating Entropy Key will be listed as 'Running OK'. You can also use the 'stats' command along with a device index or serial number to get detailed statistics for a specific device. Overview -------- The Entropy Key is a hardware random number generator. Two independent streams of noise are processed within the USB device to produce a stream of strongly random 32-byte blocks. The USB device continuously verifies each part of this process to ensure the hardware is performing correctly and will immediately cease output of entropy should a fault condition be detected. The entropy is then encrypted with a 256 bit session key negotiated with the host daemon to ensure any third party monitoring the exchange between the device and the host will be unable to know or alter the random data retrieved from the device. The ekeyd daemon communicates with the USB device, decrypts the stream, and writes the random data to the configured output stream. The ekeyd daemon can be queried and controlled using commands on a control socket. There may be more than one control socket at a time and they may be either TCP or on-local-filesystem UNIX domain sockets. Contact Details --------------- Email: For general queries - ekey@simtec.co.uk For product support - support@simtec.co.uk Website: Entropy Key site - http://www.entropykey.co.uk/ Simtec Electronics site - http://www.simtec.co.uk/ Telephone: For sales: +44 (0)1772 978010 Mail: Simtec Electronics, Avondale Drive, Tarleton, Preston, Lancs PR4 6AX United Kingdom ekeyd-1.1.5/doc/README.protocol0000664000175000017500000004445511556361136013743 0ustar pmpmEntropy Key Protocol (Version 0) ================================ The Entropy Key communicates to the host in packets, while the host communicates to the device in a simple byte stream. The packets from the device to the host are framed to make it easy to view a stream in a text console or serial terminal emulator such as hyperterminal or minicom. All examples in this document will be taken from the Entropy Key with the serial number NwBvBlg3OTBJORFD. Hashes and MACs --------------- Whenever we talk about using a Skein hash in the Entropy Key protocol or associated documentation, we are talking about the 256 bit Skein hash as described on http://www.skein-hash.info/ set to output at 256 bits. Skein provides for personalisation strings which are used to ensure that even if the same data is hashed for different purposes, it will not produce the same hash. For the Entropy Key, the personalisation strings related to the protocol are: RS: "20090609 support@simtec.co.uk EntropyKey/v1/ReKeyingState " PMS: "20090609 support@simtec.co.uk EntropyKey/v1/MessageAuthenticationCodeState " EES: "20090609 support@simtec.co.uk EntropyKey/v1/EntropyEncryptionState " LRS: "20090609 support@simtec.co.uk EntropyKey/v1/LongTermReKeyingState " LKMS: "20090609 support@simtec.co.uk EntropyKey/v1/MessageAuthenticationCodeStateForLongTermReKeying " Note that the spaces *are* part of the personalisation strings, but the quote marks (") *are not* part of the strings. The RS string is used to personalise the hash which creates the Session Keys. The PMS personalises the state which is used to create the MACs you see on each packet. The EES is used to personalise the hash which creates the one-time-pads for the E! packets. The LRS is used to personalise the hash which creates the Long-Term Keys and the LKMS is used to personalise the hash which is used to MAC the host's nonce for rekeying the Long-Term Key. Whenever a Skein 256-256 state is used, it is prepared as follows: A Skein 256-256 state in TREE_INFO_SEQUENTIAL mode is created using the concatenation of the serial number of the device (as 12 bytes of binary, not 16 characters of PEM) and a 32 byte (256 bit) secret. The Skein is then switched into personalisation input mode and the 96 character personalisation string is fed to the Skein. The Skein is then switched back into message input mode ready for the message. Thus, when we talk about a Skein, personalised by the RS, keyed with the Long-Term Key, the following is performed: Skein_256_Init_Ex(&state, 256, SKEIN_CFG_TREE_INFO_SEQUENTIAL, concatenationof(serialnumber, longtermkey), 44); Skein_Start_New_Type(skein, PERS); Skein_256_Update(skein, RS_personalisationstring, 96); Skein_Start_New_Type(skein, MSG); This is in the PrepareSkein function of the sample host software in the skeinwrap.c file which can be found in the device directory. The two ways in which a Skein state can be finalised are _Final and _Final_Pad. The former is used for hashing and the latter is used for MACs. In both cases, 256 bit output is generated. MACs are presented as the first 24 bits and last 24 bits of the 256 bit output, PEM encoded and concatenated. PEM encoding ------------ Whenever binary information is to be transmitted, either to, or from the device, it is PEM encoded. The particular PEM encoding used by the Entropy Key is PEM64 with the following dictionary: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" The character '=' is used to indicate filler, so if only one byte is to be PEM encoded, it will appear somewhat like: 'AA==', if two bytes are encoded 'AAA=' and if three bytes are encoded 'AAAA'. Each (up-to) three byte input is encoded into four characters of PEM64 output. PEM encode and decode functions can be found in pem.c in the device/frames directory of the sample host software. Framing ------- Each packet (or frame) sent from the Entropy Key device to the host is 64 bytes long. It consists of four sections. The 'Start-Of-Frame' (SOF) marker, the content of the frame, the MAC for the content, and the 'End-Of-Frame' (EOF) marker. The SOF is '* ' and the EOF is '\r\n' (Characters 13 and 10). If the host has received 64 bytes whose start and end match those markers, then it has received a frame and it can proceed to the next level of checking. The MAC is calculated over the content of the frame and is the eight PEM characters directly preceeding the EOF. The content over which the MAC is calculated is therefore 52 characters long. The MAC is calculated using a Skein personalised by the PMS and keyed with the Session key which then has the packet's content added to it, before being finalised with the _Final_Pad variant of the Skein finalisation. Packet contents --------------- Once the MAC has been verified, the next layer of the frame can be peeled back. Each frame consists of a frame type and then the frame content. The frame type is a single character indicating which kind of frame it is, and then a character indicating the frame's encoding. Text frames (>) --------------- Frames with the '>' character for their encoding type are text frames and the remaining 50 characters in the frame are considered to be unencoded text. Text frames are padded with spaces to make their content a full 50 characters in length. These spaces are not considered part of the payload of the frame, but are important when calculating the MAC. Binary frames (!) ----------------- Frames with the '!' character for their encoding type are binary frames and they have two parts to their payload. First, two characters are a PEM64 12 bit value called the sub-code or the extra-information field. The remaining 48 characters comprise up to twelve PEM quads (decoding to up-to 36 bytes) which comprise the actual payload of the frame. If not all PEM quads are used, then the frame is padded with spaces to make it up to the full size. Breakdown of a frame -------------------- Binary frames look like this: * S!AANwBvBlg3OTBJORFD Al/Smw1b 1123445555555555555555666666666666666666666666666666667777777788 1. SOF 2. Frame type 3. Frame encoding 4. Binary frame sub-code or extra-information field. 5. Binary frame payload 6. Padding 7. MAC 8. EOF (The \r\n) Text frames look like this: * I>T03143 V03254 apKTNVoy 1123444444444444455555555555555555555555555555555555556666666677 1. SOF 2. Frame type 3. Frame encoding 4. Text frame payload 5. Padding 6. MAC 7. EOF (The \r\n) Serial Number Frames -------------------- Serial number frames have the type 'S' and are binary frames. The serial number frame is the only one which is guaranteed to remain consistent between versions of the Entropy Key protocol. You can reset the Entropy Key and provoke a serial number frame by sending ^C at any time (ASCII character 3). This is described below. The serial number frame for our example key looks like this: * S!AANwBvBlg3OTBJORFD Al/Smw1b The sub-code field is 'AA' which decodes to 0x000 and indicates version 0 of the Entropy Key protocol. This document describes version 0 of the protocol. The rest of the payload 'NwBvBlg3OTBJORFD' is the PEM encoded serial number of the device and will be identical to the serial number which can be retrieved from the USB device descriptor. When a serial number frame is received, it can be assumed that the session key has been reset to zero. (i.e. the session key is 32 bytes all zero) and thus the MAC can be checked to ensure that the packet has not become corrupted. Out-Of-Sequence-Numbers (Re-Key Me) Frames ------------------------------------------ When the device has generated and verified a 20000 bit block of entropy ready for sending to the host, but it has run out of sequence numbers (or has yet to be given a Session Key at all) it will issue a re-key me packet. They look as follows: * k>Unable to send entropy. Please re-key session. VqrrSb4k The actual text of the packet is unimportant and is filled out purely to make it clear to a human observer what the meaning of the packet is. The lower-case 'k' is all that is relevant. Information Frames ------------------ Periodically the device will generate information frames which provide data about the internal states of the device. Information frames are indicated by the 'I' frame type and are text frames. Information frames carry a payload of the form: {:}* i.e. a type character tells the host what information follows, and then some number of colon separated ascii-encoded integers. The number of integers is dependent on the type of information. A frame may carry multiple of these information blocks, separated by a space character. Version 0 of the protocol defines the following types: T: The temperature of the core of the Entropy Key. V: The primary voltage of the Entropy Key F: Snapshot of the state of the FIPS 140-2 monitors. S: Snapshot of the state of the generators and the key itself. The temperature of the entropy key is supplied as an integer representing tenths of a Kelvin. The voltage is supplied as an integer representing millivolts. For example: * I>T03150 V03254 6ihYwAqo This frame indicates a temperature of 315.0 K which is approximately 42 degrees Celsius, or 107 degrees Fahrenheit), and a voltage of 3.254 volts. The FIPS snapshot consists of five numbers. The first is the number of FIPS 140-2 frames (20000 bits) which have been processed since the counters last reset. The second number indicates the total number of failures in that sample set. The third number indicates how many of those failures failed the 'monobit' test. The fourth number indicates how many of the failures failed the 'poker' test. The fifth number indicates how many of the failures failed the 'runs' test. For example: * I>F07342:00000:00000:00000:00000 1L9eG/G8 This frame indicates that in the past 7342 frames, none have failed the FIPS 140-2 tests. The state snapshot frame consists of nine values. * I>S08052:23751:23792:23584:07112:20876:08063:24150:0Sr3rR9o3 As can be seen here, the state snapshot fills the frame entirely. If we break the frame down, we get: 08052:23751:23792:23584 This indicates that in this snapshot, 8052 bytes have been read from the quantum effect generators (64416 bits). The "left-hand" generator stream has an estimated 23751 shannons of entropy in total, the "right-hand" generator stream has an estimated 23792 shannons of entropy in total. The exclusive-OR of the two streams has an estimated 23584 shannons of entropy in total. These indicators will reset every 80Kbit of raw data read of the two internal generators. 07112:20876 This indicates that the "left-hand" stream when debiassed has an estimated 20876 shannons of entropy in 7112 bytes. 08063:24150 This indicates that the "right-hand" stream when debiassed has an estimated 24150 shannons of entropy in 8063 bytes. 0 This indicates that the Entropy Key device has not detected any intrusion or failure mode. This value is in fact not a simple ascii-encoded integer, but is a character which takes on the values in daemon/failmodes.h in the sample host software: 0: No failure 1: Left generator is no longer random 2: Right generator is no longer random 3: Generators have become correlated 4: Left generator is strongly biassed 5: Right generator is strongly biassed 7: Temperature detected below threshold 8: Temperature detected above threshold 9: FIPS 140-2 tests exceeded threshold for failed blocks A: Voltage too low B: Voltage too high Session re-key frames --------------------- When rekeying the session, the host sends a nonce to the device. In response, the device sends 32 bytes of entropy in a binary re-key frame. Directly after this frame has been sent, the session key is recalculated. * K!AA6XxLwelzehWDH8ofVA7moL76KiQj0ruKmqs9T7ygW/Q= Qkbxfpr4 The sub-code (extra-information) field indicates how many bytes of nonce the device received in the re-keying instruction. Entropy frames -------------- Entropy frames are binary frames whose sub-code (extra-information) field indicates the sequence number of the entropy packets. The payload is a 256 bit (32 byte) entropy packet which has been encrypted. * E!UYIYK1Z/uc21bcnUi9QF37X+rgByqWP+RJdvcaSBWNBhY= OIq9Dvd3 The encryption is performed by taking a Skein state personalised with the EES, keyed with the session key; updating it with the two characters of PEM encoded sequence number and then finalising it before exclusive-ORing it with the entropy to be transmitted. Long-Term-Rekey MAC acknowledge frames -------------------------------------- When the client sends Mxxxxxxxx to indicate the MAC of the nonce it is about to send in order to rekey the Long-Term key, the device responds with an 'M' frame. The content of the frame is irrelevant and provided only for human observers. * M>Long-term rekey unlocked vrHSYIoF All that is relevant in this frame is the 'M' and that its MAC is valid. Long-Term-Rekey acknowledge frames ---------------------------------- When rekeying the long-term key, the host sends a nonce to the device. In response, the device sends 32 bytes of entropy in a binary long-term-re-key frame. Directly after this frame has been sent, the long-term key is recalculate and stored to non-volatile storage on the device. * L!AA6XxLwelzehWDH8ofVA7moL76KiQj0ruKmqs9T7ygW/Q= Qkbxfpr4 The sub-code (extra-information) field indicates the number of bytes of nonce which have been received by the device. The rest of the packet is the entropy to use to create the new long-term key. Long-Term-Rekey failure frames ------------------------------ If the long-term-rekey request fails for any reason, the device responds with an 'l' frame. For example, either of the following may be returned: * l>Long-term rekey locked-out m/wvdw2F * l>Nonce MAC does not match 6l+FxwYn The 'l' is the only significant part of this packet. The textual description of the failure mode is provided only for human observers. Unknown input frames -------------------- Should the host send an unexpected or incomprehensible byte to the device, the device will respond with an unknown-input frame. Any other bytes received in that USB packet will be discarded. * W>Unknown Input Character 0x65 TRNC7UwS The only significant part of this frame to the host is the 'W', the text content is provided only for human observers. Generators have gone bad frames ------------------------------- During the re-keying process (either for session or long-term key) if the generators go bad (or an attack is detected) then the rekeying operation will be abandoned and a 'B' frame will be emitted. * B>Generators have gone bad, rekeying abandoned. Dv+8RVaa The only significant part of this frame to the host is the 'B', the text content is provided for human observers. Subsequent to receiving such a frame, should the host wish to know what failure mode was encountered, it should wait for an information frame indicating the state snapshot of the device. Communication from the host to the device ----------------------------------------- The communication from the host to the device takes the form of a byte stream. Most commands are single bytes, followed by some amount of arguments and then a terminator where needed. The only command byte which is *always* accepted no matter what state the device is in, is ^C (ASCII character 3) which will reset the state machines on the device. NOTE: Resetting the state machines will not remove the fail-mode lockout on a device. To achieve that you must power down the device. Reset command ------------- The Entropy Key will reset upon receipt of a ^C (ASCII character 3) or, if idle, upon receipt of 'R' or 'r'. After reset, the device will send a serial number packet to start the exchange. Session re-key command ---------------------- When the host wants to re-key the session with the device, it sends a 'k' or 'K' followed by some number of PEM quads which encode the nonce which the host wishes to use in the re-keying process. Once all the PEM quads have been transmitted, the host sends a '.' to signify that it is ready to re-key. The device responds with a K! packet (see above) and subsequently recalculates the session key for itself. The session key is calculated by taking a Skein personalised with the RS, keyed with the long-term-key, into which is mixed the entropy from the device, and then the nonce from the host, before being finalised to produce a 256 bit key. Long-Term-Rekey Nonce MAC command --------------------------------- When the host wishes to re-key the long-term-key, it first creates a nonce and then creates a MAC for the nonce by preparing a Skein personalised with the LKMS and keyed with the master key, updating it with the nonce, and then finalising it with _Final_Pad. The first 24 bits and last 24 bits of the MAC are then PEM encoded and sent to the device with this command. This command is 'M' or 'm', followed by the eight PEM characters (two pem quads) which comprise the MAC of the nonce. The device responds with an acknowledgement (M>). Long-Term re-key command ------------------------ When the host wishes to re-key the long-term key, it first produces and sends the nonce MAC command as above, then it PEM encodes the nonce it generated and sends this command to the device. This command is an 'L' or 'l' followed by the PEM encoded nonce and terminated by a '.' to signify the end of the nonce. The device responds by first verifying the MAC of the nonce, replying with an 'l>' packet if the nonce MAC does not match. If the nonce MAC matches then the device responds with an 'L!' packet (see above) and subsequently recalculates the long-term key and commits it to non-volatile storage. The Long-term key is derived by taking a Skein personalised with the LRS, keyed with the master key, updating it with the entropy from the device and then the nonce from the host, and then finalising it to produce the 256 bit long-term key. ekeyd-1.1.5/COPYING0000664000175000017500000000206511613247672011502 0ustar pmpmCopyright Simtec Electronics 2009-2011 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ekeyd-1.1.5/host/0002775000175000017500000000000011672145156011422 5ustar pmpmekeyd-1.1.5/host/keydb.c0000664000175000017500000001070411624426325012661 0ustar pmpm/* daemon/keydb.c * * Entropy key keys database handling. * * Copyright 2009 Simtec Electronics * * For licence terms refer to the COPYING file. */ #include #include #include #include #include #include #include #include #include "keydb.h" #include "pem.h" /** Keyring entry. */ struct snum_to_key_s { struct snum_to_key_s *next; /**< Next entry. */ uint8_t snum[12]; /**< Serial number. */ uint8_t ltkey[32]; /**< Long term session key. */ }; static struct snum_to_key_s *ents = NULL; /** Find a long term saession key from a serial number. * * @param snum The serial number to find the key for. * @return The keyring entry or NULL if no matching serial number is found. */ static struct snum_to_key_s * find_ltkey(const uint8_t *snum) { struct snum_to_key_s *ent = ents; while (ent != NULL) { if (memcmp(ent->snum, snum, 12) == 0) break; ent = ent->next; } return ent; } /* exported interface documented in keydb.h */ uint8_t * snum_to_ltkey(const uint8_t *snum) { struct snum_to_key_s *ent; uint8_t *key = NULL; ent = find_ltkey(snum); if (ent != NULL) { key = malloc(32); if (key != NULL) { memcpy(key, ent->ltkey, 32); } } return key; } /* exported interface documented in keydb.h */ int output_key(FILE *fh, const uint8_t *snum, const uint8_t *ltkey) { uint8_t data[128]; pem64_encode_bytes(snum, 12, (char *)data); data[16] = ' '; pem64_encode_bytes(ltkey, 32, (char *)data + 17); data[61] = 0; return fprintf(fh, "%s\n", data); } /* exported interface documented in keydb.h */ int add_ltkey(const uint8_t *snum, const uint8_t *ltkey) { struct snum_to_key_s *ent; ent = find_ltkey(snum); if (ent == NULL) { /* no current entry for that serial number */ ent = calloc(1, sizeof(struct snum_to_key_s)); memcpy(ent->snum, snum, 12); ent->next = ents; ents = ent; } memcpy(ent->ltkey, ltkey, 32); return 0; } /* exported interface documented in keydb.h */ int write_keyring(const char *keyring_fname) { int fd; FILE *fh; struct snum_to_key_s *base = ents; char *tmpkeyring_fname; /* create temporary keyring file name */ tmpkeyring_fname = malloc(strlen(keyring_fname) + 5); if (tmpkeyring_fname == NULL) { perror("malloc"); return -1; } strcpy(tmpkeyring_fname, keyring_fname); strcat(tmpkeyring_fname, ".tmp"); /* write keyring to new file */ fd = open(tmpkeyring_fname, O_CREAT | O_EXCL | O_WRONLY, 0600); if (fd == -1) { /* Unable to open keyring */ perror("open"); free(tmpkeyring_fname); return -1; } fh = fdopen(fd, "w"); if (fh == NULL) { /* Unable to create stdio stream */ perror("fdopen"); free(tmpkeyring_fname); close(fd); return -1; } fprintf(fh, "# Do not edit this directly, this file is managed by ekey-setkey\n"); while (base) { output_key(fh, base->snum, base->ltkey); base = base->next; } fflush(fh); fclose(fh); /* rename temporary file to target */ if (rename(tmpkeyring_fname, keyring_fname) == -1) { perror("rename"); unlink(tmpkeyring_fname); free(tmpkeyring_fname); return -1; } free(tmpkeyring_fname); return 0; } /* exported interface documented in keydb.h */ int read_keyring(const char *fname) { FILE *fh; char line[512]; char snumpem[17]; char ltkeypem[45]; int res; int keys = 0; uint8_t snum[12]; uint8_t ltkey[33]; struct snum_to_key_s *base = ents; fh = fopen(fname, "r"); if (fh == NULL) { /* Unable to open keyring */ return -1; } /* Blow the old keyring out of the water */ while (base) { struct snum_to_key_s *next = base->next; free(base); base = next; } ents = NULL; while (fgets(line, 512, fh) != NULL) { res = sscanf(line, " %16[A-Za-z0-9+/=] %44[A-Za-z0-9+/=]", snumpem, ltkeypem); if (res == 2) { pem64_decode_bytes(snumpem, 16, snum); pem64_decode_bytes(ltkeypem, 44, ltkey); add_ltkey(snum, ltkey); keys++; } } fclose(fh); return keys; } ekeyd-1.1.5/host/stats.c0000664000175000017500000000402411430013510012676 0ustar pmpm/* daemon/stats.c * * Entropy key daemon statistics handling * * Copyright 2009 Simtec Electronics * * For licence terms refer to the COPYING file. */ #include #include #include #include "ekeyd.h" #include "stream.h" #include "frame.h" #include "packet.h" #include "connection.h" #include "stats.h" /* exported interface, documented in stats.h */ connection_stats_t * get_key_stats(OpaqueEkey *ekey) { connection_stats_t *stats; if (ekey == NULL) return NULL; stats = calloc(1, sizeof(connection_stats_t)); if (stats == NULL) return NULL; /* values held in ekey structure we already checked is valid */ stats->con_start = ekey->con_start; stats->con_pkts = ekey->con_pkts; stats->con_reset = ekey->con_reset; stats->con_nonces = ekey->con_nonces; stats->con_rekeys = ekey->con_rekeys; stats->con_entropy = ekey->con_entropy; stats->key_temp = ekey->key_temp; stats->key_voltage = ekey->key_voltage; stats->key_badness = ekey->key_badness; stats->fips_frame_rate = ekey->fips_frame_rate; stats->key_raw_entl = ekey->key_raw_entl; stats->key_raw_entr = ekey->key_raw_entr; stats->key_raw_entx = ekey->key_raw_entx; stats->key_dbsd_entl = ekey->key_dbsd_entl; stats->key_dbsd_entr = ekey->key_dbsd_entr; /* stats held in stream structure */ if (ekey->key_stream != NULL) { stats->stream_bytes_read = ekey->key_stream->bytes_read; stats->stream_bytes_written = ekey->key_stream->bytes_written; } /* stats held in packet structure */ if (ekey->epkt != NULL) { stats->pkt_error = ekey->epkt->pkt_error; stats->pkt_ok = ekey->epkt->pkt_ok; /* stats held in frame structure */ if (ekey->epkt->frame != NULL) { stats->frame_byte_last = ekey->epkt->frame->byte_last; stats->frame_framing_errors = ekey->epkt->frame->framing_errors; stats->frame_frames_ok = ekey->epkt->frame->frames_ok; } } return stats; } ekeyd-1.1.5/host/frame.h0000664000175000017500000000241211304563124012651 0ustar pmpm/* daemon/frame.h * * Framing interface for ekey protocol. * * Copyright 2009 Simtec Electronics * * For licence terms refer to the COPYING file. */ #ifndef DAEMON_FRAME_H #define DAEMON_FRAME_H #define EFRAME_LEN 64 #define SOF0 '*' #define SOF1 ' ' #define EOF0 13 #define EOF1 10 /** Entropy key packet framer context. */ typedef struct { estream_state_t *stream; /**< Stream to read input from. */ /* current frame info */ uint8_t frame[EFRAME_LEN]; /**< Frame data. */ int used; /**< Amount of data currently used in frame. */ /* statistics */ uint64_t byte_last; /**< Index of begining of last correct frame */ uint32_t framing_errors; /**< Number of framing errors */ uint32_t frames_ok; /**< Number of valid frames. */ } eframe_state_t; /** Create a new framing context. * * @param stream_state The stream on which to put the framer. * @return The new frame state. */ extern eframe_state_t *eframe_open(estream_state_t *stream_state); /** Close framing context. * * @param state The frame state to finalise. * @return 0 */ extern int eframe_close(eframe_state_t *state); /** Read framed data. * * @param state The frame state to read from. */ extern ssize_t eframe_read(eframe_state_t *state); #endif /* DAEMON_FRAME_H */ ekeyd-1.1.5/host/crc8.c0000664000175000017500000000075211304563124012416 0ustar pmpm/* daemon/crc8.c * * CCITT CRC-8 implementation. * * Copyright 2009 Simtec Electronics * * For licence terms refer to the COPYING file. */ #include #include #include "crc8.h" /* documented in crc8.h */ uint8_t crc8(const uint8_t *dp, ssize_t size) { uint8_t crc = 0xff; int b; while (size-- > 0) { crc ^= *dp; dp++; for (b = 0; b < 8; b++) { if (crc & 0x80) crc = (crc << 1) ^ 0x31; else crc <<= 1; } } return crc; } ekeyd-1.1.5/host/ekey-rekey.80000664000175000017500000000377011634140431013557 0ustar pmpm.TH ekey-rekey 8 "14th September 2011" .SH NAME ekey-rekey - Entropy Key Long Term Session Key tool .SH SYNOPSIS .B ekey-rekey [ \-d DeviceNode ] [SerialNumber [MasterKey]] .SH DESCRIPTION .PP .I ekey-rekey is a tool which sets the long-term key of an Entropy Key using its Master Key. It ensures any running ekey daemons are updated with the altered keys. .SH "OPTIONS" .TP .B SerialNumber Specifies the serial number of the key to re-key. If this is not specified, the identity of the Entropy Key currently connected will be automatically detected. .TP .B MasterKey Specifies the Master Key of the device being re-keyed. If this is not specified, the user will be prompted for it. .TP .B DeviceNode If \-d or \-\-device is specified, then the tool expects to be give the device node to use (such as /dev/ttyACM0) rather than attempting to work it out from the serial number provided. .SH "SEE ALSO" ekey-setkey(8), ekeyd(8) .SH AUTHOR Copyright \(co 2011 Simtec Electronics. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ekeyd-1.1.5/host/ekey-setkey.c0000664000175000017500000002664411634140431014024 0ustar pmpm/* daemon/lt-rekey.c * * Entropy key long term re-keying tool. * * Copyright 2009 Simtec Electronics * * For licence terms refer to the COPYING file. */ #include #include #include #include #include #include #include #include #include #include #include "pem.h" #include "skeinwrap.h" #include "util.h" #include "nonce.h" #include "crc8.h" #include "stream.h" #include "frame.h" #include "packet.h" #include "keydb.h" #define STDIN 0 /** Exit code returned when utility is unable to validate command line */ #define EXIT_CODE_CMDLINE 1 /** Exit code returned when utility is unable to read keyring */ #define EXIT_CODE_LOADKEYRING 2 /** Exit code returned when master key is unusable */ #define EXIT_CODE_MASTERKEY 3 /** Exit code returned when entropy key device is inacessible */ #define EXIT_CODE_EKEYERR 4 /** Exit code returned when utility is unable to write updated keyring */ #define EXIT_CODE_WRITEKEYRING 6 #define DEVEKEY "/dev/entropykey/" /** Conenction state. */ struct econ_state_s { uint8_t *mkey; /**< Master key. */ uint8_t *snum; /**< Serial number */ estream_state_t *key_stream; /**< The input stream. */ eframe_state_t *eframer; /**< The framer attached to the stream. */ epkt_state_t *epkt; /**< The packet handler attached to the framer. */ }; static uint8_t default_session_key[32]; static char reset[] = {0x3}; uint8_t * calc_mac(uint8_t *snum, uint8_t *mkey, uint8_t *nonce, int nonce_len) { EKeySkein sk_mac; uint8_t macbuf[32]; uint8_t *mac; mac = calloc(1, 6); PrepareSkein(&sk_mac, snum, mkey, EKEY_SKEIN_PERSONALISATION_LKMS); Skein_256_Update(&sk_mac, nonce, nonce_len); Skein_256_Final_Pad(&sk_mac, macbuf); mac[0] = macbuf[0]; mac[1] = macbuf[1]; mac[2] = macbuf[2]; mac[3] = macbuf[29]; mac[4] = macbuf[30]; mac[5] = macbuf[31]; return mac; } static const char *usage = "This is a low level tool. You probably wanted to use ekey-rekey instead.\n\n" "Usage: %s [-d] [-h] [-n] [-f ] [-m ]\n" " [-s ] \n" "Entropy key device long term session key tool\n\n" "\t-v Print version and exit.\n" "\t-h Print this help text and exit.\n" "\t-n Do not update the keyring with the result.\n" "\t-f The path to the keyring to update.\n" "\t-m The master key of the device being updated.\n" "\t-s The serial number of the device being updated.\n\n"; int get_keyring(const char *keyring_filename) { int res; res = read_keyring(keyring_filename); if (res < 0) { fprintf(stderr, "Unable to read the keyring file %s (%s).\n", keyring_filename, strerror(errno)); return -1; } return res; } char * strdupcat(const char *s1, const char *s2) { char *rs; int s1_l, s2_l; s1_l = strlen(s1); s2_l = strlen(s2); rs = calloc(1, s1_l + s2_l + 1 ); memcpy(rs, s1, s1_l); memcpy(rs + s1_l, s2, s2_l); return rs; } int put_keyring(const char *keyring_filename) { int res; char *tmp_keyring_filename; tmp_keyring_filename = strdupcat(keyring_filename, ".new"); res = write_keyring(tmp_keyring_filename); if (res < 0) { fprintf(stderr, "Unable to write the keyring file %s (%s).\n", tmp_keyring_filename, strerror(errno)); free(tmp_keyring_filename); return -1; } res = rename(tmp_keyring_filename, keyring_filename); if (res < 0) { fprintf(stderr, "Unable to replace keyring file %s with %s(%s).\n", keyring_filename, tmp_keyring_filename, strerror(errno)); } free(tmp_keyring_filename); return res; } uint8_t * extract_master_key(const char *s, int len) { uint8_t *mkey = NULL; /** Master key. */ int res; uint8_t crc; mkey = malloc(33); if (mkey == NULL) return NULL; res = pem64_decode_bytes(s, len, mkey); if (res == 33) { /* 33 bytes in pem - last byte should be crc8 checksum */ crc = crc8(mkey, 32); if (crc != mkey[32]) { fprintf(stderr, "The provided master key's check digit is incorrect.\n" "Please check for typing errors and character substitution.\n"); free(mkey); return NULL; } } else if (res != 32) { fprintf(stderr, "The key given did not decode to the correct length. (%d/32)\n", res); free(mkey); return NULL; } return mkey; } int main(int argc, char **argv) { uint8_t *mkey = NULL; /** Master key. */ uint8_t *snum = NULL; /** Serial number */ char *key_path = NULL; estream_state_t *key_stream ; /** The input stream. */ epkt_state_t *epkt; /* The packet handler attached to the framer. */ int opt; int res; uint8_t data[128]; uint8_t nonce[12]; uint8_t *mac; EKeySkein rekeying_state; uint8_t session_key[32]; int retries; char *keyring_filename; bool nokeyring = false; keyring_filename = strdup(KEYRINGFILE); while ((opt = getopt(argc, argv, "vhnf:s:m:")) != -1) { switch (opt) { case 's': /* set serial number */ snum = malloc(12); res = pem64_decode_bytes(optarg, 16, snum); if (res != 12) { fprintf(stderr, "The serial number given is not the correct length. (%d/12)\n", res); return EXIT_CODE_CMDLINE; } break; case 'm': /* set master key */ mkey = extract_master_key(optarg, strlen(optarg)); if (mkey == NULL) return EXIT_CODE_CMDLINE; break; case 'f': /* set keyring filename */ free(keyring_filename); keyring_filename = strdup(optarg); break; case 'n': /* do not update the keyring */ nokeyring = true; break; case 'v': /* print version number */ printf("%s: Version 1.1\n", argv[0]); return 0; case 'h': default: fprintf(stderr, usage, argv[0]); return EXIT_CODE_CMDLINE; } } if (optind >= argc) { if (snum == NULL) { fprintf(stderr, "A device path must be given.\n"); fprintf(stderr, usage, argv[0]); return EXIT_CODE_CMDLINE; } else { key_path = calloc(1, 17 + strlen(DEVEKEY)); memcpy(key_path, DEVEKEY, 1 + strlen(DEVEKEY)); pem64_encode_bytes(snum, 12, key_path + 16); } } else { key_path = strdup(argv[optind]); } /* load keyring */ if (nokeyring == false) { if (get_keyring(keyring_filename) < 0) { free(key_path); return EXIT_CODE_LOADKEYRING; } } /* ensure master key */ if (mkey == NULL) { char s[55]; int sidx; int sodx; int slen; if (isatty(STDIN) == 0) { fprintf(stderr, "A master key must be given.\n"); free(key_path); return EXIT_CODE_MASTERKEY; } printf("Please enter a master key: "); if (fgets(s, sizeof(s), stdin) == NULL) { perror("fgets"); } /* we must allow for the user entering spaces in the input */ slen = strlen(s); sidx = sodx = 0; while ((sidx < slen) && (s[sidx] != 0)) { s[sodx] = s[sidx]; if (s[sidx] != ' ') { sodx++; } sidx++; } s[sodx] = 0; mkey = extract_master_key(s, sodx); if (mkey == NULL) { free(key_path); return EXIT_CODE_MASTERKEY; } } /* open entropy key device */ key_stream = estream_open(key_path); if (key_stream == NULL) { perror("Error"); fprintf(stderr, "Unable to open %s as the entropy key device.\n", key_path); free(key_path); return EXIT_CODE_EKEYERR; } free(key_path); epkt = epkt_open(eframe_open(key_stream)); /* reset key */ estream_write(key_stream, reset, 1); epkt_setsessionkey(epkt, NULL, default_session_key); /* wait for serial packet */ retries = 20; do { res = epkt_read(epkt, data, 128); if (res <= 0) { if (errno == EWOULDBLOCK) continue; perror("Unexpected error"); return 2; } else if (epkt->pkt_type == PKTTYPE_SNUM) { break; } /* reset key */ estream_write(key_stream, reset, 1); epkt_setsessionkey(epkt, NULL, default_session_key); retries--; } while (retries > 0); if (retries == 0) { fprintf(stderr, "Timeout obtaining serial number from key.\n"); return 3; } if (res != 12) { fprintf(stderr, "Bad serial number from key.\n"); return 4; } if (snum == NULL) { /* no serial number */ snum = malloc(res); memcpy(snum, data, res); } else { /* ensure serial number matches */ if (memcmp(snum, data, 12) != 0) { fprintf(stderr, "Serial number did not match the one specified.\n"); return 4; } } /* Initialise the MAC checksum using the serial number and the default * shared key */ epkt_setsessionkey(epkt, snum, default_session_key); /* Prepare a nonce */ if (fill_nonce(nonce, 12) != true) { fprintf(stderr, "Unable to generate nonce.\n"); return 1; } close_nonce(); /* send nonce MAC */ mac = calc_mac(snum, mkey, nonce, 12); data[0] = 'M'; pem64_encode_bytes(mac, 6, (char *)data + 1); estream_write(key_stream, data, 9); /* wait for MAC ack packet */ retries = 20; do { res = epkt_read(epkt, data, 128); if (res <= 0) { if (errno == EWOULDBLOCK) continue; perror("Unexpected error"); return 2; } if (epkt->pkt_type == PKTTYPE_LTREKEYMAC) break; retries--; } while (retries > 0); if (retries == 0) { fprintf(stderr, "Timeout obtaining MAC acknowledgement packet.\n"); return 3; } data[0] = 'L'; data[17] = '.'; pem64_encode_bytes(nonce, 12, (char *)data + 1); estream_write(key_stream, data, 18); /* wait for rekey ack packet */ do { res = epkt_read(epkt, data, 128); if (res <= 0) { if (errno == EWOULDBLOCK) continue; if (errno == EPROTO) { fprintf(stderr, "Provided master key does not match the device's.\n"); return 2; } perror("Unexpected error"); return 2; } } while (epkt->pkt_type != PKTTYPE_LTREKEY); /* calculate new longterm key */ PrepareSkein(&rekeying_state, snum, &(mkey[0]), EKEY_SKEIN_PERSONALISATION_LRS); Skein_256_Update(&rekeying_state, &(data[0]), 32); Skein_256_Update(&rekeying_state, nonce, 12); Skein_256_Final(&rekeying_state, session_key); if (nokeyring == false) { add_ltkey(snum, session_key); if (put_keyring(keyring_filename) < 0) return EXIT_CODE_WRITEKEYRING; } else { /* just display new key */ output_key(stdout, snum, session_key); } return 0; } ekeyd-1.1.5/host/keydb.h0000664000175000017500000000317611624426325012673 0ustar pmpm/* daemon/keydb.h * * Keyring input/management * * Copyright 2009 Simtec Electronics * * For licence terms refer to the COPYING file. */ #ifndef DAEMON_KEYDB_H #define DAEMON_KEYDB_H #include /** * (re-)Initialise the key database and read a keyring into it. * * @param fname The file to read the keyring from. * @return -1 with errno set on failure, otherwise returns the number of keys read. * @note Format is "PEMSerial PEMLTK\n" * nkeys. */ extern int read_keyring(const char *fname); /** * Write the current keyring to a file. * * To be idempotent a temporary file is written and renamed to the filename. * * @param keyfilename The name of the keyring file to be written. * @return The number of entries written or -1 and errno set. */ int write_keyring(const char *keyfilename); /** * Retrieve a long-term-key by serial number. * * @param snum The serial number of the LTK to retrieve. * @return A pointer to the LTK, or NULL if not found. * @note The returned pointer is owned by the caller. It is * the caller's responsibility to free it when it is * finished with it. */ extern uint8_t *snum_to_ltkey(const uint8_t *snum); /** * Add a long term session key to the keyring. * * @param snum Serial number of the key. * @param ltkey The long term session key. */ int add_ltkey(const uint8_t *snum, const uint8_t *ltkey); /** * Format a serial number and long term session key for output to a stream. * * @param snum Serial number of the key. * @param ltkey The long term session key. */ int output_key(FILE *fh, const uint8_t *snum, const uint8_t *ltkey); #endif /* DAEMON_KEYDB_H */ ekeyd-1.1.5/host/stats.h0000664000175000017500000000423111430013510012703 0ustar pmpm/* daemon/stats.h * * Interface to Entropy Key statistics * * Copyright 2009 Simtec Electronics * * For licence terms refer to the COPYING file. */ #ifndef DAEMON_STATS_H #define DAEMON_STATS_H /** Unified statistics. */ typedef struct { uint64_t stream_bytes_read; /**< Number of bytes read from the stream. */ uint64_t stream_bytes_written; /**< Number of bytes written to the stream. */ uint64_t frame_byte_last; /**< Index of begining of last correct frame. */ uint32_t frame_framing_errors; /**< Number of framing errors. */ uint32_t frame_frames_ok; /**< Number of valid frames. */ uint32_t pkt_error; /**< Number of packets with an error. */ uint32_t pkt_ok; /**< Number of ok packets. */ time_t con_start; /**< Time the connection was started. */ uint32_t con_pkts; /**< Number of processed packets. */ uint32_t con_reset; /**< The number of times the connection has encounterd a reset condition. */ uint32_t con_nonces; /**< The number of times a nonce has been sent. */ uint32_t con_rekeys; /**< The number of times the session key has been set. */ uint64_t con_entropy; /**< The number of bytes of entropy recived. */ int key_temp; /**< Last reported key temerature in deci-kelvin. */ int key_voltage; /**< Last internal supply voltage reported by key. */ char key_badness; /**< badness indicator \see control.lua */ uint32_t fips_frame_rate; /**< Number of fips frames generated. */ uint32_t key_raw_entl; /**< raw estimated shanons per bit of left input. */ uint32_t key_raw_entr; /**< raw estimated shanons per bit of right input. */ uint32_t key_raw_entx; /**< raw estimated shanons per bit after xor. */ uint32_t key_dbsd_entl; /**< debiased shanons per bit of left input. */ uint32_t key_dbsd_entr; /**< debiased shanons per bit of right input. */ } connection_stats_t; /** Create a unified statistics structure from an entropy key connection state. * * @note The returned structure must be freed by the caller. * * @param ekey The connection context. * @return A statistics structure. */ connection_stats_t *get_key_stats(OpaqueEkey *ekey); #endif /* DAEMON_STATS_H */ ekeyd-1.1.5/host/crc8.h0000664000175000017500000000036611242333722012424 0ustar pmpm/* daemon/ekeyd.h * * Interface to Entropy Keys * * Copyright 2009 Simtec Electronics * * For licence terms refer to the COPYING file. */ #ifndef DAEMON_CRC8_H #define DAEMON_CRC8_H uint8_t crc8(const uint8_t *dp, ssize_t size); #endif ekeyd-1.1.5/host/packet.c0000664000175000017500000001352011304563124013023 0ustar pmpm/* daemon/packet.c * * Entropy key packet handling * * Copyright 2009 Simtec Electronics * * For licence terms refer to the COPYING file. */ #include #include #include #include #include #include #include "pem.h" #include "skeinwrap.h" #include "util.h" #include "stream.h" #include "frame.h" #include "packet.h" /* exported interface documented in packet.h */ epkt_state_t * epkt_open(eframe_state_t *frame_state) { epkt_state_t *pkt_state; if (frame_state == NULL) return NULL; pkt_state = calloc(1, sizeof(epkt_state_t)); if (pkt_state == NULL) return NULL; pkt_state->frame = frame_state; return pkt_state; } /* exported interface documented in packet.h */ int epkt_close(epkt_state_t *state) { if (state != NULL) { eframe_close(state->frame); if (state->sk_mac != NULL) free(state->sk_mac); free(state); } return 0; } /* exported interface documented in packet.h */ void epkt_setsessionkey(epkt_state_t *state, uint8_t *snum, uint8_t *sessionkey) { if (snum == NULL) return; if(sessionkey == NULL) return; if (state->sk_mac != NULL) free(state->sk_mac); state->sk_mac = calloc(1, sizeof(EKeySkein)); PrepareSkein(state->sk_mac, snum, sessionkey, EKEY_SKEIN_PERSONALISATION_PMS); } /** Check the current packets MAC is valid. * * @param state The packet processing state. * @return true if the MAC is valid false if it is incorrect. */ static bool verify_mac(epkt_state_t *state) { EKeySkein pkt_mac_sk; uint8_t macbuf[32]; uint8_t pkt_mac[6]; uint8_t *pem_mac; uint8_t *frame; if (state->sk_mac == NULL) return false; frame = state->frame->frame; pem_mac = frame + 54; /* decode PEM encoded MAC */ pem64_decode_bytes((char *)pem_mac, 8, pkt_mac); memcpy(&pkt_mac_sk, state->sk_mac, sizeof(pkt_mac_sk)); Skein_256_Update(&pkt_mac_sk, frame + 2, 52); Skein_256_Final_Pad(&pkt_mac_sk, macbuf); if ((memcmp(macbuf, pkt_mac, 3) != 0) || (memcmp(macbuf + 29, pkt_mac + 3, 3) != 0)) { return false; } return true; } /** Verify incoming packet is well formed. * * @param state The packet processing state. * @return zero if the packet is valid or -1 and errno set. */ static int verify_packet(epkt_state_t *state) { uint8_t *frame; frame = state->frame->frame; if ((frame[3] != PKT_CLASS_ASCII) && (frame[3] != PKT_CLASS_BINARY)) { state->pkt_error++; errno = EINVAL; /* unknown packet class */ return -1; } if ((state->sk_mac == NULL) && (state->pkt_type == PKTTYPE_SNUM)) { /* serial number packets MAC dont have to pass if the skein hasnt * been initialised because we dont have the serial number yet! */ state->pkt_ok++; return 0; } if (verify_mac(state) == false) { state->pkt_error++; state->pkt_type = PKTTYPE_KEYREJECTED; /* packet failed mac */ } else { state->pkt_ok++; } return 0; } /** Determine the packet type. * * Decode the packet type from the frame data. * * @param state A frame state. * @return The packet type. */ static pkt_type_t get_pkt_type(eframe_state_t *state) { switch (state->frame[2]) { case 'S': return PKTTYPE_SNUM; case 'I': return PKTTYPE_INFO; case 'W': return PKTTYPE_WARN; case 'E': return PKTTYPE_ENTROPY; case 'k': return PKTTYPE_KEYREQ; case 'K': return PKTTYPE_KEY; case 'M': return PKTTYPE_LTREKEYMAC; case 'L': return PKTTYPE_LTREKEY; default: return PKTTYPE_NONE; } return PKTTYPE_NONE; } /** Extract and decode the contents of a packet. * * @param state The packet state. * @param buf The buffer to place the output data in. * @param count the size of \a buf. * @return The length of the decoded data or -1 and errno set. */ static ssize_t decode_packet(epkt_state_t *state, uint8_t *buf, size_t count) { uint8_t *frame; int len; frame = state->frame->frame; if (frame[3] == PKT_CLASS_BINARY) { /* decode PEM encoded data */ //printf("decoding: %.48s\n", frame + 6); len = pem64_decode_bytes((char *)(frame + 6), 48, buf); //printf("decoded: %s\n", phex(buf,len)); state->subcode[0] = frame[4]; state->subcode[1] = frame[5]; } else { /* ASCII packet find the end of data */ for (len = 50; len > 0 ; len--) { if (frame[len + 3] != ' ') break; } //printf("copying: %.*s\n", len,frame + 4); memcpy(buf, frame + 4, len); buf[len] = 0; /* null terminate the string */ state->data_len = len; state->subcode[0] = 0; state->subcode[1] = 0; } return len; } /* exported interface documented in packet.h */ short epkt_get_pemsubcode(epkt_state_t *state) { return pem64_decode_12bits((char *)state->subcode); } /* exported interface documented in packet.h */ ssize_t epkt_read(epkt_state_t *state, uint8_t *buf, size_t count) { int frame_len; frame_len = eframe_read(state->frame); if (frame_len <= 0) { return frame_len; /* propogate error */ } /* Clear used data from framer context. This means the frame data is only * safe to reference until the next call to eframe_read() */ state->frame->used = 0; /* find the type of packet we are dealing with */ state->pkt_type = get_pkt_type(state->frame); if (state->pkt_type == PKTTYPE_NONE) { errno = EPROTO; return -1; } /* verify the packets type and MAC */ if (verify_packet(state) < 0) { return -1; /* propogate error */ } /* decode packets data */ return decode_packet(state, buf, count); } ekeyd-1.1.5/host/fds.c0000664000175000017500000000513411304563124012332 0ustar pmpm/* daemon/fds.c * * Entropy key file descriptor poll handling. * * Copyright 2009 Simtec Electronics * * For licence terms refer to the COPYING file. */ #include #include "fds.h" #define MAX_EKEY_POLLFD 256 typedef struct { ekeyfd_pollfunc_t func; void *pw; } ekeyfd_pollent_t; static struct pollfd ekeyfd_pollfd[MAX_EKEY_POLLFD]; static ekeyfd_pollent_t ekeyfd_funcs[MAX_EKEY_POLLFD]; static int ekeyd_lastfd = 0; /* exported interface, documented in fds.h */ int ekeyfd_add(int fd, short events, ekeyfd_pollfunc_t func, void *pw) { ekeyfd_pollfd[ekeyd_lastfd].fd = fd; ekeyfd_pollfd[ekeyd_lastfd].events = events; ekeyfd_funcs[ekeyd_lastfd].func = func; ekeyfd_funcs[ekeyd_lastfd].pw = pw; ekeyd_lastfd++; return ekeyd_lastfd; } /* exported interface, documented in fds.h */ int ekeyfd_rm(int fd) { int fdloop; for (fdloop = 0 ; fdloop < ekeyd_lastfd ; fdloop++) { if (ekeyfd_pollfd[fdloop].fd == fd) { ekeyd_lastfd--; if (fdloop != ekeyd_lastfd) { ekeyfd_pollfd[fdloop].fd = ekeyfd_pollfd[ekeyd_lastfd].fd; ekeyfd_pollfd[fdloop].events = ekeyfd_pollfd[ekeyd_lastfd].events; ekeyfd_funcs[fdloop].func = ekeyfd_funcs[ekeyd_lastfd].func; ekeyfd_funcs[fdloop].pw = ekeyfd_funcs[ekeyd_lastfd].pw; } } } return 0; } /* exported interface, documented in fds.h */ void ekeyfd_set_events(int fd, short events) { int fdloop; for (fdloop = 0 ; fdloop < ekeyd_lastfd ; fdloop++) { if (ekeyfd_pollfd[fdloop].fd == fd) { ekeyfd_pollfd[fdloop].events |= events; } } } /* exported interface, documented in fds.h */ void ekeyfd_clear_events(int fd, short events) { int fdloop; for (fdloop = 0 ; fdloop < ekeyd_lastfd ; fdloop++) { if (ekeyfd_pollfd[fdloop].fd == fd) { ekeyfd_pollfd[fdloop].events &= ~events; } } } /* exported interface, documented in fds.h */ int ekeyfd_poll(int timeout) { int rdy; int fdcnt = 0; int fdloop = 0; if (ekeyd_lastfd == 0) { return 0; } rdy = poll(ekeyfd_pollfd, ekeyd_lastfd, timeout); if (rdy > 0) { for (fdloop = 0 ; ((fdcnt < rdy) && (fdloop < ekeyd_lastfd)) ; fdloop++) { if (ekeyfd_pollfd[fdloop].revents != 0) { fdcnt++; ekeyfd_funcs[fdloop].func(ekeyfd_pollfd[fdloop].fd, ekeyfd_pollfd[fdloop].revents, ekeyfd_funcs[fdloop].pw); } } } return rdy; } ekeyd-1.1.5/host/packet.h0000664000175000017500000000510511304563124013030 0ustar pmpm/* daemon/packet.h * * Packetisation layer for ekey protocol * * Copyright 2009 Simtec Electronics * * For licence terms refer to the COPYING file. */ #ifndef DAEMON_PACKET_H #define DAEMON_PACKET_H #include "skeinwrap.h" typedef enum { PKTTYPE_NONE = 0, PKTTYPE_KEYREJECTED, /** Packets MAC was rejected. */ PKTTYPE_SNUM, /**< Serial number. */ PKTTYPE_INFO, /**< Informational. */ PKTTYPE_WARN, /**< Warning. */ PKTTYPE_ENTROPY, /**< Entropy data. */ PKTTYPE_KEYREQ, /**< Key request. */ PKTTYPE_KEY, /**< Session key response. */ PKTTYPE_LTREKEYMAC, /**< Long term rekey mac successful. */ PKTTYPE_LTREKEY, /**< Long termrekey successful. */ PKTTYPE_SIZE /* used to size state array, *must* be last */ } pkt_type_t; /** Entropy key packet processor state. */ typedef struct { pkt_type_t pkt_type; /**< The type of the current packet. */ uint8_t subcode[2]; /**< The sub-code of the current packet. */ int data_len; /**< The length of the current packet. */ eframe_state_t *frame; /**< The framer to read from. */ EKeySkein *sk_mac; /**< The precomputed MAC skein. */ /* statistics */ uint32_t pkt_error; /**< The number of packet errors. */ uint32_t pkt_ok; /**< The number of successfully processed packets. */ } epkt_state_t; #define PKT_CLASS_ASCII '>' #define PKT_CLASS_BINARY '!' #ifndef EPROTO /* OpenBSD lacks EPROTO (Protocol error) */ #define EPROTO 71 #endif /** Create a packet processor state read for use. * * @param frame_state The framer to attach teh packet processor to. * @return The new packet processing state or NULL and errno set on error. */ extern epkt_state_t *epkt_open(eframe_state_t *frame_state); /** Finish packet processor state read for use. * * @param state The packet processing state. */ extern int epkt_close(epkt_state_t *state); /** Read a complete packet. * * Read a complete packet and decode it into its elements. * * @param state The packet processing state. * @param buf The buffer to place the result data in. * @param count The length of \a buf. * @return The length of the data placed in \a buf or -1 and errno set. */ extern ssize_t epkt_read(epkt_state_t *state, uint8_t *buf, size_t count); /** Obtain the two subcode bytes. * * Read the two subcode bytes of teh current packet. * * @param state The packet processing state. */ extern short epkt_get_pemsubcode(epkt_state_t *state); /** Set the session key to be used for MAC generation. */ extern void epkt_setsessionkey(epkt_state_t *state, uint8_t *snum, uint8_t *sharedkey); #endif /* DAEMON_PACKET_H */ ekeyd-1.1.5/host/util.c0000664000175000017500000000105511304563124012531 0ustar pmpm/* daemon/util.c * * Entropy key daemon utility functions * * Copyright 2009 Simtec Electronics * * For licence terms refer to the COPYING file. */ #include #include "util.h" static char hexa[16] = "0123456789ABCDEF"; /* exported interface, documented in util.h */ char * phex(uint8_t *c, int l) { static char text[128]; int loop; for (loop = 0 ; loop < l ; loop++) { text[(loop * 2) + 1] = hexa[(c[loop] & 0xF)]; text[loop * 2] = hexa[(c[loop] & 0xF0) >> 4]; } text[loop*2] = 0; return text; } ekeyd-1.1.5/host/ekey-ulusbd.80000664000175000017500000000411711300265007013727 0ustar pmpm.TH ekey-ulusbd 8 "12 Aug 2009" .SH NAME ekey-ulusbd - Entropy Key, Userland USB Daemon .SH SYNOPSIS .B ekeyd \-b \fIbusnum\fR \-d \fIbusnum\fR \-p \fIsocketpath\fR [ \-P \fIpidfile\fR ] [ \-D ] [ \-v ] [ \-h ] .SH DESCRIPTION .PP .I ekey-ulusbd is a daemon which connects to a Simtec Entropy Key device and provides a UNIX domain socket at \fIsocketpath\fR for the ekeyd(8) to connect to. .SH OPTIONS .TP \fB\-b\fR \fIbusnum\fR Specify the bus number that the device is on (e.g. \fB003\fR). .TP \fB\-d\fR \fIdevnum\fR Specify the dev number of the device (e.g. \fB005\fR). .TP \fB\-p\fR \fIsocketpath\fR Specify the path to the UNIX domain socket to be created. .TP \fB\-P\fR \fIpidfile\fR Specify the name and path of the file used to record the \fBekeyd\fR process ID. .TP \fB\-D\fR Daemonise rather than remaining attached to the terminal it is run from. .TP .B \-h Print the usage text and exit. .TP .B \-v Print the version number and exit. .SH "SEE ALSO" ekeyd(8) ekeyd.conf(5), ekey-rekey(8), ekey-setkey(8) .SH AUTHOR Copyright \(co 2009 Simtec Electronics. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ekeyd-1.1.5/host/control.lua0000664000175000017500000005766211430013510013577 0ustar pmpm-- daemon/setup.lua -- -- Entropy Key Initialisation, configuration and management code. -- -- Copyright 2009 Simtec Electronics -- The low-level C API provided to us. local addfd = _addfd local delfd = _delfd local writefd = _writefd local nowritefd = _nowritefd local ekey_add = _add_ekey local ekey_del = _del_ekey local ekey_query = _query_ekey local ekey_stat = _stat_ekey local read_keys = _load_keys local open_output_file = _open_output_file local open_kernel_output = _open_kernel_output local open_foldback_output = _open_foldback_output local daemonise = _daemonise local unlink = _unlink local chmod = _chmod local chown = _chown local enumerate = _enumerate local gc = collectgarbage local debugprint = function() end -- Use print to output debugging if debugprint == print then -- if we're debugging, ensure we don't daemonise by default. -- a Daemonise(true) in the config will override this. _daemonise(false) end -- Constants and useful values local PROTOCOL_VERSION = "1" -- DOS Protection local dos_callcount = 0 -- Libraries we need require "socket" local have_unix_domain_sockets = false function tryload_unix() require "socket.unix" have_unix_domain_sockets = true end pcall(tryload_unix) local protectedenv = {} -- Control socket interface local controlsockets = {} local ctlwritebuffers = {} local ctlreadbuffers = {} local ctlpendingcmd = {} local ctltokill = {} local ctldielater = {} local ctltoaccept = {} local ctlenv = {} local ctlrhandler = {} function addctlsocket(sock, name, isconn, rhandler) --print("New " .. (isconn and "control" or "connection") .. " socket: " .. name) controlsockets[sock] = name controlsockets[name] = sock ctlreadbuffers[sock] = "" ctltoaccept[sock] = not isconn addfd(sock:getfd()) local newenv = {} local newmeta = {__index=protectedenv} setmetatable(newenv, newmeta) ctlenv[sock] = newenv ctlrhandler[sock] = rhandler end function delctlsocket(sock) local name = controlsockets[sock] if (type(name) ~= "string") then name, sock = sock, name end controlsockets[sock] = nil controlsockets[name] = nil if ctlwritebuffers[sock] then ctlwritebuffers[sock] = nil nowritefd(sock:getfd()) end ctlreadbuffers[sock] = nil ctlpendingcmd[sock] = nil ctltokill[sock] = nil ctltoaccept[sock] = nil ctldielater[sock] = nil ctlenv[sock] = nil ctlrhandler[sock] = nil delfd(sock:getfd()) sock:close() end function ctlwrite(sockorname, str) local sock = type(sockorname) == "string" and controlsockets[sockorname] or sockorname local curw = ctlwritebuffers[sock] if str == nil or str == "" then -- Pointless write attempt. return end ctlwritebuffers[sock] = (curw and curw or "") .. str if not curw then writefd(sock:getfd()) end end function _ctldowrite(sock) -- Yes, this one always gets a socket local str = ctlwritebuffers[sock] if (ctltokill[sock]) then return end local written = sock:send(str) if (written == 0) then return end debugprint("Written:",tostring(written)) if written == nil then ctltokill[sock] = true end if written == #str then ctlwritebuffers[sock] = nil nowritefd(sock:getfd()) if ctldielater[sock] then ctltokill[sock] = true end return end ctlwritebuffers[sock] = string.sub(str, written + 1) end function _ctldoread(sock) -- Yes, this one always gets a socket too if ctlrhandler[sock] then return ctlrhandler[sock](sock) end -- Not got a specific handler, so check on and assume it's a control socket if ctltoaccept[sock] then local client = sock:accept() --print "Done accept" client:settimeout(0.010) --print "Done timeout" pcall(function() client:setoption("tcp-nodelay", true) end) --print "Done option" local peer, maybeport = "UNIX", 0 pcall(function() peer, maybeport = client:getpeername() end) --print "Done peername" if maybeport then peer = peer .. ":" .. tostring(maybeport) end --print "made peer" local name = "C:" .. peer --print "made name" addctlsocket(client, name, true) --print "ctlsocket added" ctlwrite(client, "PROTOCOL EKEYD/" .. PROTOCOL_VERSION .. "\n") return end local r,msg = sock:receive() if r == nil or r == 0 then ctltokill[sock] = true return end ctlpendingcmd[sock] = r end -- Output management local output_configured = false -- Entropy Key management local ekey_list = {} local ekey_nr = 1 local failmodes = { ["0"] = { "efm_ok", "No failure" }, ["1"] = { "efm_raw_left_bad", "Left generator is no longer random" }, ["2"] = { "efm_raw_right_bad", "Right generator is no longer random" }, ["3"] = { "efm_raw_xor_bad", "Generators have become correlated" }, ["4"] = { "efm_debias_left_bad", "Left generator is strongly biassed" }, ["5"] = { "efm_debias_right_bad", "Right generator is strongly biassed" }, ["7"] = { "efm_temp_too_low", "Temperature detected below threshold" }, ["8"] = { "efm_temp_too_high", "Temperature detected above threshold" }, ["9"] = { "efm_fips1402_threshold_exceeded", "FIPS 140-2 tests exceeded threshold for failed blocks"}, ["A"] = { "efm_volt_too_low", "Voltage too low" }, ["B"] = { "efm_volt_too_high", "Voltage too high" }} local function update_ekey_stat(ekey) ekey.stats = ekey_stat(ekey.ekey) ekey.stats["EntropyRate"] = math.floor((ekey.stats["TotalEntropy"] * 8) / ekey.stats["ConnectionTime"]) ekey.stats["KeyTemperatureK"] = ekey.stats["KeyTemperatureK"] / 10; ekey.stats["KeyTemperatureC"] = ekey.stats["KeyTemperatureK"] - 273.15; ekey.stats["KeyTemperatureF"] = (ekey.stats["KeyTemperatureK"] * 1.8) - 459.67; ekey.stats["KeyVoltage"] = ekey.stats["KeyVoltage"] / 1000; ekey.stats["KeyRawShannonPerByteL"] = ekey.stats["KeyRawShannonPerByteL"] / 100; ekey.stats["KeyRawShannonPerByteR"] = ekey.stats["KeyRawShannonPerByteR"] / 100; ekey.stats["KeyRawShannonPerByteX"] = ekey.stats["KeyRawShannonPerByteX"] / 100; ekey.stats["KeyDbsdShannonPerByteL"] = ekey.stats["KeyDbsdShannonPerByteL"] / 100; ekey.stats["KeyDbsdShannonPerByteR"] = ekey.stats["KeyDbsdShannonPerByteR"] / 100; ekey.stats["FipsFrameRate"] = ekey.stats["FipsFrameRate"] / 100; ekey.stats["ReadRate"] = math.floor((ekey.stats["BytesRead"] * 8) / ekey.stats["ConnectionTime"]) ekey.stats["WriteRate"] = math.floor((ekey.stats["BytesWritten"] * 8) / ekey.stats["ConnectionTime"]) ekey.stats["KeyShortBadness"] = failmodes[ekey.stats["KeyRawBadness"]][1] ekey.stats["KeyEnglishBadness"] = failmodes[ekey.stats["KeyRawBadness"]][2] end local function update_ekey(ekey) ekey.okay, ekey.status, ekey.serial = ekey_query(ekey.ekey) end function add_ekey(path, serial) assert(output_configured, "No output type yet configured") local ekey = find_ekey(path) if ekey then -- Already got it return ekey end ekey = { nr = ekey_nr, devpath = path, ekey = assert(ekey_add(path, serial)), stats = { } } update_ekey(ekey) table.insert(ekey_list, ekey) ekey_list[ekey] = #ekey_list ekey_list[ekey.ekey] = ekey ekey_nr = ekey_nr + 1 return ekey end function find_ekey(tag) tag = tostring(tag) debugprint("Looking for " .. tag) for _, ekey in ipairs(ekey_list) do if type(ekey) ~= "table" then debugprint("Odd",_,"is",tostring(ekey)) else update_ekey(ekey) debugprint("Checking ekey from ", tostring(ekey.devpath), "serial", tostring(ekey.serial),"nr",tostring(ekey.nr), "suffix",string.sub(tostring(ekey.devpath),-#tag, -1)) if (tostring(ekey.devpath) == tag) or (tostring(ekey.serial) == tag) or (tostring(ekey.nr) == tag) or (string.sub(tostring(ekey.devpath),-(#tag + 1),-1) == "/"..tag) then return ekey, _ end end end end function kill_ekey(ekey) local new_tab = {} for _, nekey in ipairs(ekey_list) do if ekey ~= nekey then new_tab[#new_tab + 1] = nekey new_tab[nekey] = #new_tab new_tab[nekey.ekey] = nekey end end ekey_del(ekey.ekey) ekey_list = new_tab end -- EGD and other entropy-over-socket type protocols local entropy_blocks = {} local total_entropy = 0 local MAX_ENTROPY = 1024*1024 local strsub = string.sub local strbyte = string.byte local strchar = string.char local tremove = table.remove local function enqueue_entropy(bytes) if ((total_entropy + #bytes) <= MAX_ENTROPY) then entropy_blocks[#entropy_blocks + 1] = bytes total_entropy = total_entropy + #bytes --debugprint("Total entropy now " .. tostring(total_entropy) .. " bytes.") end end local function dequeue_entropy(nbytes) local retstr = "" while total_entropy > 0 and nbytes > 0 do local eval = entropy_blocks[#entropy_blocks] if #eval <= nbytes then retstr = retstr .. eval nbytes = nbytes - #eval tremove(entropy_blocks, #entropy_blocks) total_entropy = total_entropy - #eval else retstr = retstr .. strsub(eval, 1, nbytes) total_entropy = total_entropy - nbytes entropy_blocks[#entropy_blocks] = strsub(eval, nbytes + 1) nbytes = 0 end end return retstr end local weakkeyed = { __mode = "k" } local readbuffers = setmetatable({}, weakkeyed) local egdwriteblocked = setmetatable({}, weakkeyed) local egdreadblocked = setmetatable({}, weakkeyed) local function egd_getbytes(sock, nr) local r = readbuffers[sock] or "" if #r < nr then return end local t = {} for i = 1, nr do t[i] = strbyte(r, i) end readbuffers[sock] = strsub(r, nr + 1) return unpack(t) end local function egd_pushbackread(sock, bval) readbuffers[sock] = strchar(bval) .. (readbuffers[sock] or "") end local EGD_CMD_QUERYPOOL = 0 local EGD_CMD_READBYTES = 1 local EGD_CMD_BLOCKREAD = 2 local EGD_CMD_ADDENTROPY = 3 local EGD_CMD_GETPID = 4 local function egd_pack32(val) local r r = strchar(math.mod(val, 256)) val = math.floor(val / 256) r = strchar(math.mod(val, 256)) .. r val = math.floor(val / 256) r = strchar(math.mod(val, 256)) .. r val = math.floor(val / 256) r = strchar(math.mod(val, 256)) .. r return r end local function egd_try_cmd(sock) -- If blocked writing entropy, do not process commands if egdwriteblocked[sock] then --debugprint("Not servicing, write blocked") return end -- If blocked reading stuff to discard, do that first if egdreadblocked[sock] then if (egd_getbytes(sock, egdreadblocked[sock])) then --debugprint("Read unblocked") egdreadblocked[sock] = nil else -- Incomplete, do not attempt command processing --debugprint("Not servicing, read blocked") return end end -- Okay, try and process a command local cmd = egd_getbytes(sock, 1) -- Just in case there's no command... if cmd == nil then return end --debugprint("Command: " .. tostring(cmd)) if cmd == EGD_CMD_QUERYPOOL then -- Query pool size, no arguments -- Return: U32 of available entropy in bits ctlwrite(sock, egd_pack32(total_entropy * 8)) return end if cmd == EGD_CMD_READBYTES then -- Retrieve N bytes (nonblocking) -- Arguments: U8 nbytes -- Return: U8 rbytes, STR bytes local nbytes = egd_getbytes(sock, 1) if nbytes == nil then --debugprint("No request provided, pushing back") egd_pushbackread(sock, EGD_CMD_READBYTES) return end --debugprint("Dequeuing " .. tostring(nbytes)) local ent = dequeue_entropy(nbytes) --debugprint("Acquired " .. tostring(#ent)) ctlwrite(sock, strchar(#ent) .. ent) return end if cmd == EGD_CMD_BLOCKREAD then -- Retrieve N bytes (blocking) -- Arguments: U8 nbytes -- Return: STR bytes local nbytes = egd_getbytes(sock, 1) if nbytes == nil then egd_pushbackread(sock, EGD_CMD_BLOCKREAD) return end local ent = dequeue_entropy(nbytes) ctlwrite(sock, ent) if #ent < nbytes then egdwriteblocked[sock] = nbytes - #ent end return end if cmd == EGD_CMD_ADDENTROPY then -- Add entropy -- Arguments: U16 shannons, U8 bytes, STR -- Return: None local foo, bar, nbytes = egd_getbytes(sock, 3) if foo == nil then egd_pushbackread(sock, EGD_CMD_ADDENTROPY) return end --debugprint("Expect " .. tostring(nbytes)) if (egd_getbytes(sock, nbytes) == nil) then egdreadblocked[sock] = nbytes end return end if cmd == EGD_CMD_GETPID then -- Get PID -- Arguments: None -- Return U8 slen, STR pidstr ctlwrite(sock, strchar(2) .. "-1") return end -- Unknown command debugprint("Unknown EGD command: " .. tostring(cmd)) ctltokill[sock] = true end local function egd_spreadwrite() -- If there are any EGD sockets blocked on entropy, try feeding it around. if next(egdwriteblocked) == nil then return end debugprint("Doing a spreadwrite") local totpending = 0 for k, v in pairs(egdwriteblocked) do totpending = totpending + v end if (totpending > MAX_ENTROPY) then debugprint("Somehow, we are blocking for more entropy than we can ever have, skipping the test.") else if (totpending > total_entropy) then debugprint("Not enough entropy to satisfy spread-write. Want "..tostring(totpending).." but only have "..tostring(total_entropy)) return end end local to_try = {} -- Filled out with sockets we unblocked, so we can try a command. for sock, amount in pairs(egdwriteblocked) do local towrite = amount debugprint("egd_spreadwrite("..tostring(sock)..") of " .. tostring(towrite)) local got = dequeue_entropy(towrite) if #got > 0 then ctlwrite(sock, got) if towrite == amount then debugprint("huzzah, unblocked") egdwriteblocked[sock] = nil to_try[sock] = true else debugprint("boo hiss, "..tostring(amount-entper).." left") egdwriteblocked[sock] = amount - entper end end end for sock in pairs(to_try) do egd_try_cmd(sock) end end local function egd_ctlread(sock) if ctltoaccept[sock] then -- Incoming EGD connection, prepare a client connection local client = sock:accept() client:settimeout(0.010) pcall(function() client:setoption("tcp-nodelay", true) end) local peer, maybeport = "UNIX", 0 pcall(function() peer, maybeport = client:getpeername() end) if maybeport then peer = peer .. ":" .. tostring(maybeport) end local name = "EGDC:" .. peer debugprint("New client: " .. name) addctlsocket(client, name, true, egd_ctlread) readbuffers[client] = "" return end --debugprint("EGD command RX") local r,msg = sock:receive(1) if r == nil or r == 0 then debugprint("Killing") ctltokill[sock] = true return end --debugprint("Adding " .. tostring(#r) .. " bytes") readbuffers[sock] = (readbuffers[sock] or "") .. r --debugprint("Trying...") repeat egd_try_cmd(sock) r, msg = sock:receive(1) if r ~= nil then readbuffers[sock] = (readbuffers[sock] or "") .. r end until msg == "timeout" end -- The routines provided to the controlled environment local currentclient = nil local gatheredoutput = "" local gatheredlines = {} function _(f) -- Helper function to force the function environment. setfenv(_G[f], _G); protectedenv[f] = _G[f] end local output_is_folded = false local function SetFoldedOutput() if output_is_folded then return end assert(not output_configured, "Output already configured") assert(open_foldback_output()) output_configured = true output_is_folded = true end if have_unix_domain_sockets then function UnixControlSocket(sockname) -- Add a UDS control socket to the set of control sockets available -- First, try and connect, so we can abort if it's present. if socket.unix():connect(sockname) then error("Control socket " .. sockname .. " already present. Is ekeyd already running?") end -- Okay, clean up (ignoring errors) and create a fresh socket unlink(sockname) local u = socket.unix() assert(u:bind(sockname)) assert(u:listen()) addctlsocket(u, "U:" .. sockname) end _ "UnixControlSocket" else function UnixControlSocket() error("UNIX Domain sockets not supported by LuaSocket") end _ "UnixControlSocket" end function TCPControlSocket(port) -- Add a TCP control socket to the set of control sockets available if socket.tcp():connect("127.0.0.1", tonumber(port)) then error("TCP Control socket on port " .. tostring(port) .. " already present. Is ekeyd already running?") end local t = socket.tcp() t:setoption("reuseaddr", true) assert(t:bind("127.0.0.1", tonumber(port))) assert(t:listen()) addctlsocket(t, "T:" .. tostring(port)) end _ "TCPControlSocket" if have_unix_domain_sockets then function EGDUnixSocket(sockname, modestr, user, group) SetFoldedOutput() if socket.unix():connect(sockname) then error("EGD socket " .. sockname .. " already present. Is ekeyd/EGD already running?") end -- Add a UDS control socket to the set of control sockets available unlink(sockname) local u = socket.unix() assert(u:bind(sockname)) assert(u:listen()) addctlsocket(u, "U:" .. sockname, false, egd_ctlread) if modestr then assert(chmod(sockname, tonumber(modestr, 8))) user = user or "" group = group or "" assert(chown(sockname, user, group)) else assert(chmod(sockname, tonumber("0600", 8))) end end _ "EGDUnixSocket" else function EGDUnixSocket() error("UNIX Domain sockets not supported by LuaSocket") end _ "EGDUnixSocket" end function EGDTCPSocket(port, ipaddr) SetFoldedOutput() ipaddr = ipaddr or "127.0.0.1" if socket.tcp():connect(ipaddr, tonumber(port)) then error("EGD TCP socket on " .. ipaddr .. ":" .. tostring(port) .. " already present. Is ekeyd/EGD already running?") end -- Add a TCP control socket to the set of control sockets available local t = socket.tcp() t:setoption("reuseaddr", true) assert(t:bind(ipaddr, tonumber(port))) assert(t:listen()) addctlsocket(t, "T:" .. tostring(port), false, egd_ctlread) end _ "EGDTCPSocket" function Bye() Print "Good bye" ctldielater[currentclient] = true end _ "Bye" function MLPrint(...) local t = {...} for i, v in ipairs(t) do if type(v) ~= "string" then t[i] = tostring(v) end end gatheredlines[#gatheredlines+1] = table.concat(t, "\t") end _ "MLPrint" function Print(...) local t = {...} for i, v in ipairs(t) do if type(v) ~= "string" then t[i] = tostring(v) end end gatheredoutput = (gatheredoutput and gatheredoutput .. ", " or "") .. table.concat(t, "\t") end _ "Print" function KVPrint(key, value) gatheredlines[#gatheredlines+1] = key .. "=" .. value end _ "KVPrint" function AddEntropyKey(devpath, serial) local mykey = add_ekey(devpath, serial) debugprint("Added ekey for " .. tostring(devpath)) Print("ID "..tostring(mykey.nr)) end _ "AddEntropyKey" function RemoveEntropyKey(tag) local ekey = assert(find_ekey(tag), "Unable to find ekey '" .. tostring(tag) .. "'") debugprint("Killing ekey for " .. tostring(tag)) kill_ekey(ekey) end _ "RemoveEntropyKey" function AddEntropyKeys(dirname) local function do_it() for _, knode in ipairs(assert(enumerate(dirname))) do if string.sub(knode, 1, 1) ~= "." then AddEntropyKey(dirname .. "/" .. knode) end end end pcall(do_it) end _ "AddEntropyKeys" function Keyring(fname) Print(tostring(read_keys(tostring(fname)))) end _ "Keyring" function SetOutputToFile(fname) assert(not output_configured, "Output already configured") assert(open_output_file(fname)) output_configured = true end _ "SetOutputToFile" function SetOutputToKernel(bpb) assert(not output_configured, "Output already configured") assert(open_kernel_output(tonumber(bpb))) output_configured = true end _ "SetOutputToKernel" function ListEntropyKeys() MLPrint("NR", "OK", "Status", "Path", "SerialNo") for _, ekey in ipairs(ekey_list) do update_ekey(ekey) MLPrint(ekey.nr, ekey.okay and "YES" or "NO", ekey.status or "", ekey.devpath, ekey.serial) end return tostring(#ekey_list) end _ "ListEntropyKeys" function StatEntropyKey(tag) local ekey = assert(find_ekey(tag), "Unable to find ekey '" .. tostring(tag) .. "'") update_ekey_stat(ekey) for i, v in pairs(ekey.stats) do KVPrint(i, v) end end _ "StatEntropyKey" function Shutdown() while #ekey_list > 0 do kill_ekey(ekey_list[1]) end local k = next(controlsockets) while k do delctlsocket(k) k = next(controlsockets) end end _ "Shutdown" function Daemonise(val) daemonise(val) end _ "Daemonise" -- Routines to run stuff in the controlled environment local function protected_closure(client, func) return function() currentclient = client gatheredoutput = nil gatheredlines = {} local blah = func() if type(blah) == "function" then blah() end currentclient = nil return gatheredoutput end end function runprotectedcommand(client, cmd) dos_callcount = 0 local func, msg = loadstring("return " .. cmd) if not func then ctlwrite(client, "ERROR " .. msg .. "\n") return end setfenv(func, ctlenv[client]) dos_callcount = 0 local ok, msg = xpcall(protected_closure(client, func), function(m) return tostring(m) end) if ok then for _, line in ipairs(gatheredlines) do ctlwrite(client, "*\t" .. line .. "\n") end ctlwrite(client, "OK" .. (msg and " "..msg or "") .. "\n") else ctlwrite(client, "ERROR " .. msg .. "\n") end end -- Our interface as-called-from-C. function FINAL() -- Finalise any open FDs, deregister and close all sockets. -- Remove all ekeys and output modes, etc. dos_callcount = 0 local killme repeat killme = next(controlsockets, nil) if killme then delctlsocket(killme) end until killme == nil end function CONFIG(cfile) -- Prepare a controlled state and run the contents of cfile in it. dos_callcount = 0 local func = assert(loadfile(cfile)) setfenv(func, protectedenv) assert(pcall(func)) assert(next(controlsockets), "No control interface specified") protectedenv.Daemonise = nil end function CONTROL() dos_callcount = 0 -- Process anything pending on any of the control sockets. local readt, writet = {}, {} for sock in pairs(controlsockets) do if type(sock) ~= "string" then readt[#readt+1] = sock end end for sock in pairs(ctlwritebuffers) do writet[#writet+1] = sock end readt, writet = socket.select(readt, writet, 0.01) for _, reader in ipairs(readt) do _ctldoread(reader) end for _, writer in ipairs(writet) do _ctldowrite(writer) end for sock, cmd in pairs(ctlpendingcmd) do if not ctltokill[sock] then runprotectedcommand(sock, cmd) end end -- We've processed them all ctlpendingcmd = {} local killme repeat killme = next(ctltokill, nil) if killme then delctlsocket(killme) end until killme == nil debugprint("After Control: " .. tostring(math.floor(gc "count")) .. " KiB in use") end function INFORM(ekey) update_ekey(ekey_list[ekey]) debugprint("After inform: " .. tostring(math.floor(gc "count")) .. " KiB in use") end local lastused = 0 local lastent = 0 function ENTROPY(bytes) dos_callcount = 0 enqueue_entropy(bytes) egd_spreadwrite() if (debugprint == print) then local thisused = math.floor(gc "count") local thisent = math.floor(total_entropy/1024) if (thisused ~= lastused or thisent ~= lastent) then debugprint("Currently we have: " .. tostring(thisused) .. " KiB in use vs. " .. tostring(thisent) .. " KiB of stored entropy") lastused = thisused lastent = thisent end end end -- Set everything up... local function hookfunc() dos_callcount = dos_callcount + 1 if dos_callcount > 100 then debugprint("D.O.S. hook fired!") error("Operation took too long. Stopping.") end end debug.sethook(hookfunc, "", 100) ekeyd-1.1.5/host/fds.h0000664000175000017500000000226211304563124012336 0ustar pmpm/* daemon/fds.h * * Interface to poll and fd handling * * Copyright 2009 Simtec Electronics * * For licence terms refer to the COPYING file. */ #ifndef DAEMON_FDS_H #define DAEMON_FDS_H typedef void (* ekeyfd_pollfunc_t)(int fd, short events, void *pw); /** Add a filedescriptor to the poll set. * * @param fd The file descriptor to add. * @param events The events to call the poll function for. * @param func The private function to call when the fd events occour. * @param pw The private data to pass to the poll function. * @return The number of file descriptors allocated. */ int ekeyfd_add(int fd, short events, ekeyfd_pollfunc_t func, void *pw); /** Remove a file descriptor from the poll set. * * @param fd The file descriptor to remove. */ int ekeyfd_rm(int fd); /** Poll all file descriptors for activity. * * @param timeout How long to wait for activity. * @return The number of file descriptors with processed events. */ int ekeyfd_poll(int timeout); /** Set events associated with a file descriptor. */ void ekeyfd_set_events(int fd, short events); /** Clear events associated with a file descriptor. */ void ekeyfd_clear_events(int fd, short events); #endif ekeyd-1.1.5/host/util.h0000664000175000017500000000112511304563124012534 0ustar pmpm/* daemon/util.h * * Utility functions for Ekey Daemon * * Copyright 2009 Simtec Electronics * * For licence terms refer to the COPYING file. */ #ifndef DAEMON_UTIL_H #define DAEMON_UTIL_H /** Format a number of bytes in a hexidecamal textural representation. * * @param c The bytes to format. * @param l The number of byyes to format. * @return A string containing the textural representation. * @note This is intended for debugging and the returned string is only valid * untill the next call to teh function. */ extern char *phex(uint8_t *c, int l); #endif /* DAEMON_UTIL_H */ ekeyd-1.1.5/host/ekey-setkey.80000664000175000017500000000400111634140431013730 0ustar pmpm.TH ekey-setkey 8 "14th September 2011" .SH NAME ekey-setkey - Entropy Key Long Term Key programmer .SH SYNOPSIS .B ekey-setkey .RB [ \-s .IR SerialNumber ] .RB [ \-m .IR MasterKey ] path .SH DESCRIPTION .PP .I ekey-setkey is a low level tool which sets the long-term key of an Entropy Key using its Master Key. The keyring is updated with the new session key. Any running ekeyd will not be updated with the new key and may interfere with the re-keying process. Users may use the ekey-rekey tool instead as this performs the relevant ekeydctl operations to ensure any running ekeyd is updated apropriately. This is a tool for advanced users only. Most users should use .I ekey-rekey instead. .SH "OPTIONS" .TP .B \-s Specifies the serial number of the key to re-key. .TP .B \-m Specifies the Master Key of the device .TP .B path Specifies which device node to use to access the Entropy Key. .SH "SEE ALSO" ekey-rekey(8), ekeyd(8) .SH AUTHOR Copyright \(co 2009,2011 Simtec Electronics. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ekeyd-1.1.5/host/ekeydctl.in0000775000175000017500000001361311242610630013546 0ustar pmpm#!/usr/bin/env lua@LUA_V@ -- -*- Lua -*- require "socket" -- Try to load the UNIX domain sockets support pcall(function() require "socket.unix" end) function usage() io.stderr:write((([[ %1%: Control the entropy daemon. Usage: %1% [args...] Where command is one of: add Add an entropy key (dev node provided as argument). addall Add a directory full of keys (dir name provided as argument). remove Remove an entropy key (One of dev node, serial, ID as argument). list List all the entropy keys attached to the daemon. stats Show the statistics for an entropy key (One of dev node, serial, ID as argument). keyring Load a keyring (keyring filename provided as argument) shutdown Shut the entropy key daemon down. ]]):gsub("%%(%d+)%%", function(n) return ({arg[0]})[tonumber(n)] end))) end -- Utility functions do local strfind = string.find local strlen = string.len local tinsert = table.insert local strsub = string.sub function split(s, b, c) --[[ Return the elements of a delimited string. Split string \s on boundary \b and return the list of components. @param s(string) The string to split up @param b(string) The boundary to split on @param c(boolean) Correctness. If true, splitting '' returns {''} @return bits(table) The bits of \s split up on \b ]] local t = {} b = b or " " local p = strfind(s, b, 1, 1) local l = strlen(b) if (not p) then if( s ~= "" or c ) then return { s } else return {} end end while strlen(s) ~= 0 do p = strfind(s, b, 1, 1) if (p) then tinsert(t, strsub(s, 1, p - 1)) s = strsub(s, p + l, -1) else tinsert(t, s) s = "" end end return t end end -- Connectivity local __tcpcontrolport, __unixcontrolpath = nil, nil local __socket function wait_for(pattern) -- Read lines from the socket (max 3s pause) until we hit pattern. -- Return a table of all the lines, incl. the one which matches. -- On timeout, simply report the error and exit. local rett = {} local lastline repeat lastline = assert(__socket:receive()) rett[#rett + 1] = lastline if string.match(lastline, "^ERROR") then io.stderr:write(lastline .. "\n") os.exit(4) end until string.match(lastline, pattern) return rett end function connect_to_daemon() if __unixcontrolpath then __socket = socket.unix() local result, msg = __socket:connect(__unixcontrolpath) if not result then error("Unable to connect to ekeyd at " .. __unixcontrolpath .. " (" .. msg .. ") Is ekeyd running?") end elseif __tcpcontrolport then __socket = socket.tcp() local result, msg = __socket:connect("127.0.0.1", tonumber(__tcpcontrolport)) if not result then error("Unable to connect to ekeyd at 127.0.0.1:" .. tostring(__tcpcontrolport) .. " (" .. msg .. ") Is ekeyd running?") end else io.stderr:write("Unable to find control socket\n") os.exit(3) end __socket:settimeout(3) wait_for("PROTOCOL EKEYD/%d+") end function expectarg(argno, val, msg) if val ~= nil then return end io.stderr:write("Expected argument " .. tostring(argno) .. " missing: " .. msg .. "\n") os.exit(6) end -- Commands function command_list() __socket:send("ListEntropyKeys\n") local res = wait_for("^OK$") local splits = {} for _, s in ipairs(res) do splits[#splits+1] = split(s, "\t") table.remove(splits[#splits], 1) end headers = table.remove(splits, 1) table.remove(splits, table.getn(splits)) print(table.concat(headers, ",")) for _, ktab in ipairs(splits) do print(table.concat(ktab, ",")) end end function command_stats(node) expectarg(1, node, "Entropy Key Identifier") __socket:send("StatEntropyKey(" .. string.format("%q", node) .. ")\n") local res = wait_for("^OK$") res[#res] = nil table.sort(res) for i, v in ipairs(res) do v = split(v, "\t")[2] print(v) end end function command_add(node, optserial) expectarg(1, node, "Path to Entropy Key") if optseral == nil then optserial = "nil" else optserial=string.format("%q", optserial) end __socket:send("AddEntropyKey(" .. string.format("%q", node) .. "," .. optserial .. ")\n") wait_for("^OK") end function command_remove(node) expectarg(1, node, "Entropy Key Identifier") __socket:send("RemoveEntropyKey(" .. string.format("%q", node) .. ")\n") wait_for("^OK") end function command_addall(dir) expectarg(1, dir, "Path to directory of Entropy Keys") __socket:send("AddEntropyKeys(" .. string.format("%q", dir) .. ")\n") wait_for("^OK") end function command_keyring(keyring) expectarg(1, keyring, "Path to keyring file to load") __socket:send("Keyring(" .. string.format("%q", keyring) .. ")\n") wait_for("^OK") end function command_shutdown() __socket:send("Shutdown\n") end if #arg < 1 then usage() os.exit(1) end command = arg[1] cmd = _G["command_" .. command] cmdargs = {} k = 2 while arg[k] do cmdargs[k - 1] = arg[k] k = k + 1 end if (cmd == nil) then io.stderr:write("Unknown command: " .. command .. "\n") usage() os.exit(2) end -- These functions are to emulate the config file of ekeyd function SetOutputToKernel() end function AddEntropyKeys() end function AddEntropyKey() end function Keyring() end function SetOutputToFile() end function TCPControlSocket(port) __tcpcontrolport = port end function UnixControlSocket(path) __unixcontrolpath = path end function EGDUnixSocket() end function EGDTCPSocket() end function Daemonise() end assert(loadfile"@SYSCONFPREFIX@/ekeyd.conf")() function do_it() connect_to_daemon() os.exit(cmd(unpack(cmdargs)) or 0) end _, msg = xpcall(do_it, function(s) return s end) -- If we reach here, do_it had an error. io.stderr:write("Internal error: " .. msg .. "\n") os.exit(5) ekeyd-1.1.5/host/stream.c0000664000175000017500000001171111304563124013047 0ustar pmpm/* daemon/stream.c * * Entropy key daemon stream handling * * Copyright 2009 Simtec Electronics * * For licence terms refer to the COPYING file. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "stream.h" /* POSIX.1g requires to define a SUN_LEN macro for determining the * length of sockaddr_un. Of course its not available everywhere. This is the * definition from the specification when its not defined. */ #ifndef SUN_LEN #define SUN_LEN(su) (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path)) #endif /* exported function documented in stream.h */ estream_state_t * estream_open(const char *uri) { estream_state_t *stream_state; int fd; struct stat sbuf; struct termios settings; /* Attempt to stat the file */ if (stat(uri, &sbuf) == -1) { return NULL; } if (S_ISSOCK(sbuf.st_mode)) { /* Open the file as a socket */ struct sockaddr_un saddr; size_t namelen = strlen(uri) + 1; if (namelen > sizeof(saddr.sun_path)) { fprintf(stderr, "Device name (%s) too long (%u, max. %u)\n", uri, (unsigned int)namelen, (unsigned int)sizeof(saddr.sun_path)); return NULL; } fd = socket(PF_UNIX, SOCK_STREAM, 0); if (fd != -1) { saddr.sun_family = AF_UNIX; /* this is effectively a strcpy, but strcpy produces warnings * on BSD; the check above validates this operation */ memcpy(saddr.sun_path, uri, namelen); #ifdef BSD44SOCKETS saddr.sun_len = strlen(uri) #if defined(EKEY_OS_OPENBSD) || defined(EKEY_OS_MIRBSD) + 1 #endif ; #endif if (connect(fd, (struct sockaddr *)&saddr, SUN_LEN(&saddr)) == -1) { perror("connect"); close(fd); fd = -1; } } } else if (S_ISCHR(sbuf.st_mode)) { /* Open the file as a character device/tty */ fd = open(uri, O_RDWR | O_NOCTTY); if ((fd != -1) && (isatty(fd))) { if (tcgetattr(fd, &settings) == 0 ) { settings.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL | CREAD | PARODD | CRTSCTS); settings.c_iflag &= ~(BRKINT | IGNPAR | PARMRK | INPCK | ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXOFF | IXANY | IMAXBEL); settings.c_iflag |= IGNBRK; settings.c_oflag &= ~(OPOST | OCRNL | ONOCR | ONLRET); settings.c_lflag &= ~(ISIG | ICANON | IEXTEN | ECHO | ECHOE | ECHOK | ECHONL | NOFLSH | TOSTOP | ECHOPRT | ECHOCTL | ECHOKE); settings.c_cflag |= CS8 | HUPCL | CREAD | CLOCAL; #ifdef EKEY_FULL_TERMIOS settings.c_cflag &= ~(CBAUD); settings.c_iflag &= ~(IUTF8 | IUCLC); settings.c_oflag &= ~(OFILL | OFDEL | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY | OLCUC ); settings.c_oflag |= NL0 | CR0 | TAB0 | BS0 | VT0 | FF0; settings.c_lflag &= ~(XCASE); #endif settings.c_cflag |= B115200; if (tcsetattr(fd, TCSANOW, &settings) < 0) { /* Failed to set TTY attributes? */ syslog(LOG_INFO, "Failed to set TTY attributes on %s", uri); } } tcflush(fd, TCIOFLUSH); } } else { /* open the file as a plain file and seek to the end */ fd = open(uri, O_RDWR | O_NOCTTY); lseek(fd, 0, SEEK_END); } if (fd < 0) return NULL; stream_state = calloc(1, sizeof(estream_state_t)); if (stream_state == NULL) return NULL; stream_state->uri = strdup(uri); stream_state->fd = fd; stream_state->estream_read = read; stream_state->estream_write = write; return stream_state; } /* exported function documented in stream.h */ ssize_t estream_read(estream_state_t *state, void *buf, size_t count) { ssize_t rd = state->estream_read(state->fd, buf, count); if (rd > 0) state->bytes_read += rd; return rd; } /* exported function documented in stream.h */ ssize_t estream_write(estream_state_t *state, void *buf, size_t count) { ssize_t wr = state->estream_write(state->fd, buf, count); if (wr > 0) { state->bytes_written += wr; } else { syslog(LOG_ERR, "Write error %zd on %s ", wr, state->uri); } return wr; } /* exported function documented in stream.h */ int estream_close(estream_state_t *state) { close(state->fd); free(state->uri); free(state); return 0; } ekeyd-1.1.5/host/lstate.c0000664000175000017500000002627711430013510013052 0ustar pmpm/* daemon/lstate.c * * Entropy Key Daemon, Lua state for configuration and fiddling. * * Copyright 2009 Simtec Electronics * * For licence terms refer to the COPYING file. */ #include #include #include #include #include #include #include #include #include #include #include #include "lstate.h" #include "keydb.h" #include "stats.h" #include #include #include static lua_State *L_conf = NULL; static bool daemonise = true; static int l_addfd(lua_State *L) { if (lstate_cb_newfd(luaL_checkinteger(L, 1)) == false) { /* nil */ return 0; } /* Return the FD on success */ return 1; } static int l_delfd(lua_State *L) { lstate_cb_delfd(luaL_checkinteger(L, 1)); /* Return the FD on success */ return 1; } static int l_writefd(lua_State *L) { lstate_cb_writefd(luaL_checkinteger(L, 1)); /* Return the FD on success */ return 1; } static int l_nowritefd(lua_State *L) { lstate_cb_nowritefd(luaL_checkinteger(L, 1)); /* Return the FD on success */ return 1; } static int l_add_ekey(lua_State *L) { OpaqueEkey *ekey = add_ekey(luaL_checkstring(L, 1), luaL_optstring(L, 2, NULL)); if (ekey == NULL) { lua_pushnil(L); lua_pushfstring(L, "Could not construct key from '%s' (optional serial: %s). Errno was %d (%s)", luaL_checkstring(L, 1), luaL_optstring(L, 2, "not provided"), errno, strerror(errno)); return 2; } lua_pushlightuserdata(L, ekey); return 1; } static int l_del_ekey(lua_State *L) { OpaqueEkey *ekey = (OpaqueEkey *)lua_touserdata(L, 1); if (ekey != NULL) { kill_ekey(ekey); } return 1; } #define L_KEY_STAT(name,var) \ lua_pushliteral(L, #name); \ lua_pushnumber(L, key_stats->var); \ lua_settable(L, -3) static int l_stat_ekey(lua_State *L) { OpaqueEkey *ekey = (OpaqueEkey *)lua_touserdata(L, 1); connection_stats_t *key_stats; if (ekey == NULL) { lua_pushnil(L); lua_pushliteral(L, "Unable to query a NULL ekey."); return 2; } key_stats = get_key_stats(ekey); if (key_stats == NULL) { lua_pushnil(L); lua_pushliteral(L, "Unable to get statistics."); return 2; } lua_newtable(L); L_KEY_STAT(BytesRead, stream_bytes_read); L_KEY_STAT(BytesWritten, stream_bytes_written); L_KEY_STAT(FrameByteLast, frame_byte_last); L_KEY_STAT(FramingErrors, frame_framing_errors); L_KEY_STAT(FramesOk, frame_frames_ok); L_KEY_STAT(PacketErrors, pkt_error); L_KEY_STAT(PacketOK, pkt_ok); L_KEY_STAT(TotalEntropy, con_entropy); L_KEY_STAT(KeyTemperatureK, key_temp); L_KEY_STAT(KeyVoltage, key_voltage); L_KEY_STAT(FipsFrameRate, fips_frame_rate); L_KEY_STAT(ConnectionPackets, con_pkts); L_KEY_STAT(ConnectionResets, con_reset); L_KEY_STAT(ConnectionNonces, con_nonces); L_KEY_STAT(ConnectionRekeys, con_rekeys); L_KEY_STAT(KeyRawShannonPerByteL, key_raw_entl); L_KEY_STAT(KeyRawShannonPerByteR, key_raw_entr); L_KEY_STAT(KeyRawShannonPerByteX, key_raw_entx); L_KEY_STAT(KeyDbsdShannonPerByteL, key_dbsd_entl); L_KEY_STAT(KeyDbsdShannonPerByteR, key_dbsd_entr); lua_pushliteral(L, "ConnectionTime"); lua_pushnumber(L, (time(NULL) - key_stats->con_start)); lua_settable(L, -3); lua_pushliteral(L, "KeyRawBadness"); lua_pushfstring(L, "%c", key_stats->key_badness); lua_settable(L, -3); free(key_stats); return 1; } static int l_query_ekey(lua_State *L) { OpaqueEkey *ekey = (OpaqueEkey *)lua_touserdata(L, 1); int status; char *serialnumber; if (ekey == NULL) { lua_pushnil(L); lua_pushliteral(L, "Unable to query a NULL ekey."); return 2; } status = query_ekey_status(ekey); if (status < 0) { /* Errno status */ lua_pushboolean(L, false); lua_pushstring(L, strerror(-status)); return 2; } switch (status) { case EKEY_STATUS_UNKNOWN: /* Unknown state currently */ lua_pushboolean(L, true); lua_pushliteral(L, "Unknown"); break; case EKEY_STATUS_GOODSERIAL: /* Serial number is good, not got anywhere else yet. */ lua_pushboolean(L, true); lua_pushliteral(L, "Serial ok"); break; case EKEY_STATUS_UNKNOWNSERIAL: /* Serial number is not known to the keyring. */ lua_pushboolean(L, false); lua_pushliteral(L, "Serial unknown"); break; case EKEY_STATUS_BADKEY: /* Key is bad for some reason (e.g. wrong long-term-key) */ lua_pushboolean(L, false); lua_pushliteral(L, "Long-Term-Key is bad"); break; case EKEY_STATUS_GONEBAD: /* Key reported that its generators have gone bad. */ lua_pushboolean(L, false); lua_pushliteral(L, "Key has self-stopped"); break; case EKEY_STATUS_KEYED: /* Session is keyed, generating entropy. */ lua_pushboolean(L, true); lua_pushliteral(L, "Running OK"); break; case EKEY_STATUS_KEYCLOSED: /* Key has been closed for whatever reason. */ lua_pushboolean(L, false); lua_pushliteral(L, "Key closed. (Vanished?)"); break; } serialnumber = retrieve_ekey_serial(ekey); if (serialnumber != NULL) { lua_pushlstring(L, serialnumber, 16); free(serialnumber); return 3; } return 2; } static int l_load_keys(lua_State *L) { lua_pushnumber(L, read_keyring(luaL_checkstring(L, 1))); return 1; } static int l_open_file_output(lua_State *L) { if (open_file_output(luaL_checkstring(L, 1))) { return 1; } lua_pushnil(L); lua_pushfstring(L, "Cannot open %s: errno %d (%s)", luaL_checkstring(L, 1), errno, strerror(errno)); return 2; } static int l_open_kernel_output(lua_State *L) { if (open_kernel_output(luaL_optnumber(L, 1, 4))) { return 1; } lua_pushnil(L); lua_pushfstring(L, "Cannot open kernel output for %d bits per byte: errno %d (%s)", luaL_optnumber(L, 1, 4), errno, strerror(errno)); return 2; } static int l_open_foldback_output(lua_State *L) { if (open_foldback_output()) { lua_pushboolean(L, 1); /* Return true */ return 1; } lua_pushnil(L); lua_pushfstring(L, "Cannot open foldback output: errno %d (%s)", errno, strerror(errno)); return 2; } static int l_daemonise(lua_State *L) { daemonise = lua_toboolean(L, 1); return 0; } static int l_unlink(lua_State *L) { const char *fname = luaL_checkstring(L, 1); if (unlink(fname) == -1) { lua_pushboolean(L, 0); lua_pushstring(L, strerror(errno)); return 2; } return 1; } static int l_chown(lua_State *L) { struct passwd *pw; struct group *gr; const char *fname = luaL_checkstring(L, 1); const char *user = luaL_checkstring(L, 2); const char *group = luaL_checkstring(L, 3); int uid = -1, gid = -1; if (*user != 0) { errno = 0; if ((pw = getpwnam(user)) == NULL) { lua_pushboolean(L, 0); if (errno != 0) { lua_pushstring(L, strerror(errno)); } else { lua_pushfstring(L, "Unable to find username %s", user); } return 2; } uid = pw->pw_uid; } if (*group != 0) { errno = 0; if ((gr = getgrnam(group)) == NULL) { lua_pushboolean(L, 0); if (errno != 0) { lua_pushstring(L, strerror(errno)); } else { lua_pushfstring(L, "Unable to find group %s", user); } return 2; } gid = gr->gr_gid; } if (chown(fname, uid, gid) < 0) { lua_pushboolean(L, 0); lua_pushstring(L, strerror(errno)); return 2; } lua_settop(L, 1); return 1; } static int l_chmod(lua_State *L) { const char *fname = luaL_checkstring(L, 1); int mode = luaL_checknumber(L, 2); if (chmod(fname, mode) < 0) { lua_pushboolean(L, 0); lua_pushstring(L, strerror(errno)); return 2; } lua_settop(L, 1); return 1; } static int l_enumerate(lua_State *L) { const char *path = luaL_checkstring(L, 1); DIR *d; struct dirent *de; int i = 1; if ((d = opendir(path)) == NULL) { lua_pushboolean(L, 0); lua_pushstring(L, strerror(errno)); return 2; } lua_newtable(L); while ((de = readdir(d)) != NULL) { lua_pushnumber(L, i++); lua_pushstring(L, de->d_name); lua_settable(L, -3); } closedir(d); return 1; } static const luaL_Reg lstate_funcs[] = { /* FD routines */ {"_addfd", l_addfd}, {"_delfd", l_delfd}, {"_writefd", l_writefd}, {"_nowritefd", l_nowritefd}, /* EKey routines */ {"_add_ekey", l_add_ekey}, {"_del_ekey", l_del_ekey}, {"_query_ekey", l_query_ekey}, {"_stat_ekey", l_stat_ekey}, /* Keyring routines */ {"_load_keys", l_load_keys}, /* Output routines */ {"_open_output_file", l_open_file_output}, {"_open_kernel_output", l_open_kernel_output}, {"_open_foldback_output", l_open_foldback_output}, /* Daemon features */ {"_daemonise", l_daemonise}, /* OS access routines */ {"_unlink", l_unlink}, {"_chmod", l_chmod}, {"_chown", l_chown}, {"_enumerate", l_enumerate}, /* Terminator */ {NULL, NULL} }; bool lstate_init(void) { int result; lua_State *L; L_conf = L = luaL_newstate(); if (L == NULL) { fprintf(stderr, "Unable to create configuration state.\n"); return false; } luaL_openlibs(L); luaL_register(L, "_G", lstate_funcs); #include "control.inc" if (result != 0) { fprintf(stderr, "Unable to run control setup code:\n%s\n", lua_tostring(L, -1)); lua_close(L); L = NULL; return false; } return true; } void lstate_finalise(void) { lua_State *L = L_conf; lua_getglobal(L, "FINAL"); lua_pcall(L, 0, 0, 0); lua_close(L); L_conf = NULL; } bool lstate_runconfig(const char *conffile) { lua_State *L = L_conf; lua_getglobal(L, "CONFIG"); lua_pushstring(L, conffile); if (lua_pcall(L, 1, 0, 0) != 0) { fprintf(stderr, "Unable to run configuration file:\n%s\n", lua_tostring(L, -1)); return false; } return true; } void lstate_controlbytes(void) { lua_State *L = L_conf; lua_getglobal(L, "CONTROL"); lua_pcall(L, 0, 0, 0); } void lstate_inform_about_key(OpaqueEkey *ekey) { lua_State *L = L_conf; lua_getglobal(L, "INFORM"); lua_pushlightuserdata(L, ekey); lua_pcall(L, 1, 0, 0); } bool lstate_request_daemonise(void) { return daemonise; } ssize_t lstate_foldback_entropy(const unsigned char *eblock, unsigned int ecount) { lua_State *L = L_conf; lua_getglobal(L, "ENTROPY"); lua_pushlstring(L, (char *)eblock, ecount); lua_pcall(L, 1, 0, 0); return ecount; } ekeyd-1.1.5/host/egd-linux.c0000664000175000017500000002525611557352457013500 0ustar pmpm/* daemon/egd-linux.c * * Stand-alone EGD => Linux pool entropy transfer agent. * * Copyright 2009 Simtec Electronics. * Copyrithg 2010 Collabora Ltd * * For licence terms refer to the COPYING file. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "daemonise.h" #define DEFAULT_HOST "127.0.0.1" #define DEFAULT_PORT "8888" #define DEFAULT_BLOCKS 4 #define DEFAULT_READTIMEOUT 10 static const char *pidfilename = NULL; static int random_fd = 0; static int egd_fd = -1; static int shannons = 7; static unsigned int retry_time = 0; static char *host; static char *port; struct pollfd poll_fds[2] = { { .events = POLLOUT }, { .events = POLLIN } }; #define RND_POLLFD 0 #define EGD_POLLFD 1 static int bytes_waiting = 0; /* Number of bytes waiting on read*/ static void usage(FILE *stream, char **argv) { fprintf(stream, "%s: Usage:\n" \ "\n" \ "%s [options]\n" \ "\n" \ "Valid options are:\n" \ "\t-h\t\tDisplay this help.\n" \ "\t-v\t\tDisplay the version of this program.\n" \ "\t-H \tSet the host IP address to connect to.\n" \ "\t-p \tSet the port number to connect to.\n" \ "\t-b \tThe number of 1024 bit blocks to request in\n" \ "\t\t\t each transaction. (Default %d)\n" \ "\t-s \t\tSet the number of shannons per byte to S.\n" \ "\t-D \tDaemonise, writing PID to pidf.\n" \ "\t-r