This commit is contained in:
Willy-JL
2023-08-11 22:54:16 +02:00
parent 35cf740a63
commit 12004d0ef4
18 changed files with 1877 additions and 2070 deletions

View File

@@ -22,8 +22,8 @@
#include "aes.h" #include "aes.h"
static int aes_tables_inited = 0; // run-once flag for performing key static int aes_tables_inited = 0; // run-once flag for performing key
// expasion table generation (see below) // expasion table generation (see below)
/* /*
* The following static local tables must be filled-in before the first use of * The following static local tables must be filled-in before the first use of
* the GCM or AES ciphers. They are used for the AES key expansion/scheduling * the GCM or AES ciphers. They are used for the AES key expansion/scheduling
@@ -37,99 +37,94 @@ static int aes_tables_inited = 0; // run-once flag for performing key
* the GCM input, we ONLY NEED AES encryption. Thus, to save space AES * the GCM input, we ONLY NEED AES encryption. Thus, to save space AES
* decryption is typically disabled by setting AES_DECRYPTION to 0 in aes.h. * decryption is typically disabled by setting AES_DECRYPTION to 0 in aes.h.
*/ */
// We always need our forward tables // We always need our forward tables
static uchar FSb[256]; // Forward substitution box (FSb) static uchar FSb[256]; // Forward substitution box (FSb)
static uint32_t FT0[256]; // Forward key schedule assembly tables static uint32_t FT0[256]; // Forward key schedule assembly tables
static uint32_t FT1[256]; static uint32_t FT1[256];
static uint32_t FT2[256]; static uint32_t FT2[256];
static uint32_t FT3[256]; static uint32_t FT3[256];
#if AES_DECRYPTION // We ONLY need reverse for decryption #if AES_DECRYPTION // We ONLY need reverse for decryption
static uchar RSb[256]; // Reverse substitution box (RSb) static uchar RSb[256]; // Reverse substitution box (RSb)
static uint32_t RT0[256]; // Reverse key schedule assembly tables static uint32_t RT0[256]; // Reverse key schedule assembly tables
static uint32_t RT1[256]; static uint32_t RT1[256];
static uint32_t RT2[256]; static uint32_t RT2[256];
static uint32_t RT3[256]; static uint32_t RT3[256];
#endif /* AES_DECRYPTION */ #endif /* AES_DECRYPTION */
static uint32_t RCON[10]; // AES round constants static uint32_t RCON[10]; // AES round constants
/* /*
* Platform Endianness Neutralizing Load and Store Macro definitions * Platform Endianness Neutralizing Load and Store Macro definitions
* AES wants platform-neutral Little Endian (LE) byte ordering * AES wants platform-neutral Little Endian (LE) byte ordering
*/ */
#define GET_UINT32_LE(n,b,i) { \ #define GET_UINT32_LE(n, b, i) \
(n) = ( (uint32_t) (b)[(i) ] ) \ { \
| ( (uint32_t) (b)[(i) + 1] << 8 ) \ (n) = ((uint32_t)(b)[(i)]) | ((uint32_t)(b)[(i) + 1] << 8) | \
| ( (uint32_t) (b)[(i) + 2] << 16 ) \ ((uint32_t)(b)[(i) + 2] << 16) | ((uint32_t)(b)[(i) + 3] << 24); \
| ( (uint32_t) (b)[(i) + 3] << 24 ); } }
#define PUT_UINT32_LE(n,b,i) { \ #define PUT_UINT32_LE(n, b, i) \
(b)[(i) ] = (uchar) ( (n) ); \ { \
(b)[(i) + 1] = (uchar) ( (n) >> 8 ); \ (b)[(i)] = (uchar)((n)); \
(b)[(i) + 2] = (uchar) ( (n) >> 16 ); \ (b)[(i) + 1] = (uchar)((n) >> 8); \
(b)[(i) + 3] = (uchar) ( (n) >> 24 ); } (b)[(i) + 2] = (uchar)((n) >> 16); \
(b)[(i) + 3] = (uchar)((n) >> 24); \
}
/* /*
* AES forward and reverse encryption round processing macros * AES forward and reverse encryption round processing macros
*/ */
#define AES_FROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ #define AES_FROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3) \
{ \ { \
X0 = *RK++ ^ FT0[ ( Y0 ) & 0xFF ] ^ \ X0 = *RK++ ^ FT0[(Y0)&0xFF] ^ FT1[(Y1 >> 8) & 0xFF] ^ FT2[(Y2 >> 16) & 0xFF] ^ \
FT1[ ( Y1 >> 8 ) & 0xFF ] ^ \ FT3[(Y3 >> 24) & 0xFF]; \
FT2[ ( Y2 >> 16 ) & 0xFF ] ^ \ \
FT3[ ( Y3 >> 24 ) & 0xFF ]; \ X1 = *RK++ ^ FT0[(Y1)&0xFF] ^ FT1[(Y2 >> 8) & 0xFF] ^ FT2[(Y3 >> 16) & 0xFF] ^ \
\ FT3[(Y0 >> 24) & 0xFF]; \
X1 = *RK++ ^ FT0[ ( Y1 ) & 0xFF ] ^ \ \
FT1[ ( Y2 >> 8 ) & 0xFF ] ^ \ X2 = *RK++ ^ FT0[(Y2)&0xFF] ^ FT1[(Y3 >> 8) & 0xFF] ^ FT2[(Y0 >> 16) & 0xFF] ^ \
FT2[ ( Y3 >> 16 ) & 0xFF ] ^ \ FT3[(Y1 >> 24) & 0xFF]; \
FT3[ ( Y0 >> 24 ) & 0xFF ]; \ \
\ X3 = *RK++ ^ FT0[(Y3)&0xFF] ^ FT1[(Y0 >> 8) & 0xFF] ^ FT2[(Y1 >> 16) & 0xFF] ^ \
X2 = *RK++ ^ FT0[ ( Y2 ) & 0xFF ] ^ \ FT3[(Y2 >> 24) & 0xFF]; \
FT1[ ( Y3 >> 8 ) & 0xFF ] ^ \ }
FT2[ ( Y0 >> 16 ) & 0xFF ] ^ \
FT3[ ( Y1 >> 24 ) & 0xFF ]; \
\
X3 = *RK++ ^ FT0[ ( Y3 ) & 0xFF ] ^ \
FT1[ ( Y0 >> 8 ) & 0xFF ] ^ \
FT2[ ( Y1 >> 16 ) & 0xFF ] ^ \
FT3[ ( Y2 >> 24 ) & 0xFF ]; \
}
#define AES_RROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ #define AES_RROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3) \
{ \ { \
X0 = *RK++ ^ RT0[ ( Y0 ) & 0xFF ] ^ \ X0 = *RK++ ^ RT0[(Y0)&0xFF] ^ RT1[(Y3 >> 8) & 0xFF] ^ RT2[(Y2 >> 16) & 0xFF] ^ \
RT1[ ( Y3 >> 8 ) & 0xFF ] ^ \ RT3[(Y1 >> 24) & 0xFF]; \
RT2[ ( Y2 >> 16 ) & 0xFF ] ^ \ \
RT3[ ( Y1 >> 24 ) & 0xFF ]; \ X1 = *RK++ ^ RT0[(Y1)&0xFF] ^ RT1[(Y0 >> 8) & 0xFF] ^ RT2[(Y3 >> 16) & 0xFF] ^ \
\ RT3[(Y2 >> 24) & 0xFF]; \
X1 = *RK++ ^ RT0[ ( Y1 ) & 0xFF ] ^ \ \
RT1[ ( Y0 >> 8 ) & 0xFF ] ^ \ X2 = *RK++ ^ RT0[(Y2)&0xFF] ^ RT1[(Y1 >> 8) & 0xFF] ^ RT2[(Y0 >> 16) & 0xFF] ^ \
RT2[ ( Y3 >> 16 ) & 0xFF ] ^ \ RT3[(Y3 >> 24) & 0xFF]; \
RT3[ ( Y2 >> 24 ) & 0xFF ]; \ \
\ X3 = *RK++ ^ RT0[(Y3)&0xFF] ^ RT1[(Y2 >> 8) & 0xFF] ^ RT2[(Y1 >> 16) & 0xFF] ^ \
X2 = *RK++ ^ RT0[ ( Y2 ) & 0xFF ] ^ \ RT3[(Y0 >> 24) & 0xFF]; \
RT1[ ( Y1 >> 8 ) & 0xFF ] ^ \ }
RT2[ ( Y0 >> 16 ) & 0xFF ] ^ \
RT3[ ( Y3 >> 24 ) & 0xFF ]; \
\
X3 = *RK++ ^ RT0[ ( Y3 ) & 0xFF ] ^ \
RT1[ ( Y2 >> 8 ) & 0xFF ] ^ \
RT2[ ( Y1 >> 16 ) & 0xFF ] ^ \
RT3[ ( Y0 >> 24 ) & 0xFF ]; \
}
/* /*
* These macros improve the readability of the key * These macros improve the readability of the key
* generation initialization code by collapsing * generation initialization code by collapsing
* repetitive common operations into logical pieces. * repetitive common operations into logical pieces.
*/ */
#define ROTL8(x) ( ( x << 8 ) & 0xFFFFFFFF ) | ( x >> 24 ) #define ROTL8(x) ((x << 8) & 0xFFFFFFFF) | (x >> 24)
#define XTIME(x) ( ( x << 1 ) ^ ( ( x & 0x80 ) ? 0x1B : 0x00 ) ) #define XTIME(x) ((x << 1) ^ ((x & 0x80) ? 0x1B : 0x00))
#define MUL(x,y) ( ( x && y ) ? pow[(log[x]+log[y]) % 255] : 0 ) #define MUL(x, y) ((x && y) ? pow[(log[x] + log[y]) % 255] : 0)
#define MIX(x,y) { y = ( (y << 1) | (y >> 7) ) & 0xFF; x ^= y; } #define MIX(x, y) \
#define CPY128 { *RK++ = *SK++; *RK++ = *SK++; \ { \
*RK++ = *SK++; *RK++ = *SK++; } y = ((y << 1) | (y >> 7)) & 0xFF; \
x ^= y; \
}
#define CPY128 \
{ \
*RK++ = *SK++; \
*RK++ = *SK++; \
*RK++ = *SK++; \
*RK++ = *SK++; \
}
/****************************************************************************** /******************************************************************************
* *
@@ -141,71 +136,66 @@ static uint32_t RCON[10]; // AES round constants
* at system initialization to setup the tables for all subsequent use. * at system initialization to setup the tables for all subsequent use.
* *
******************************************************************************/ ******************************************************************************/
void aes_init_keygen_tables( void ) void aes_init_keygen_tables(void) {
{ int i, x, y, z; // general purpose iteration and computation locals
int i, x, y, z; // general purpose iteration and computation locals
int pow[256]; int pow[256];
int log[256]; int log[256];
if (aes_tables_inited) return; if(aes_tables_inited) return;
// fill the 'pow' and 'log' tables over GF(2^8) // fill the 'pow' and 'log' tables over GF(2^8)
for( i = 0, x = 1; i < 256; i++ ) { for(i = 0, x = 1; i < 256; i++) {
pow[i] = x; pow[i] = x;
log[x] = i; log[x] = i;
x = ( x ^ XTIME( x ) ) & 0xFF; x = (x ^ XTIME(x)) & 0xFF;
} }
// compute the round constants // compute the round constants
for( i = 0, x = 1; i < 10; i++ ) { for(i = 0, x = 1; i < 10; i++) {
RCON[i] = (uint32_t) x; RCON[i] = (uint32_t)x;
x = XTIME( x ) & 0xFF; x = XTIME(x) & 0xFF;
} }
// fill the forward and reverse substitution boxes // fill the forward and reverse substitution boxes
FSb[0x00] = 0x63; FSb[0x00] = 0x63;
#if AES_DECRYPTION // whether AES decryption is supported #if AES_DECRYPTION // whether AES decryption is supported
RSb[0x63] = 0x00; RSb[0x63] = 0x00;
#endif /* AES_DECRYPTION */ #endif /* AES_DECRYPTION */
for( i = 1; i < 256; i++ ) { for(i = 1; i < 256; i++) {
x = y = pow[255 - log[i]]; x = y = pow[255 - log[i]];
MIX(x,y); MIX(x, y);
MIX(x,y); MIX(x, y);
MIX(x,y); MIX(x, y);
MIX(x,y); MIX(x, y);
FSb[i] = (uchar) ( x ^= 0x63 ); FSb[i] = (uchar)(x ^= 0x63);
#if AES_DECRYPTION // whether AES decryption is supported #if AES_DECRYPTION // whether AES decryption is supported
RSb[x] = (uchar) i; RSb[x] = (uchar)i;
#endif /* AES_DECRYPTION */ #endif /* AES_DECRYPTION */
} }
// generate the forward and reverse key expansion tables // generate the forward and reverse key expansion tables
for( i = 0; i < 256; i++ ) { for(i = 0; i < 256; i++) {
x = FSb[i]; x = FSb[i];
y = XTIME( x ) & 0xFF; y = XTIME(x) & 0xFF;
z = ( y ^ x ) & 0xFF; z = (y ^ x) & 0xFF;
FT0[i] = ( (uint32_t) y ) ^ ( (uint32_t) x << 8 ) ^ FT0[i] = ((uint32_t)y) ^ ((uint32_t)x << 8) ^ ((uint32_t)x << 16) ^ ((uint32_t)z << 24);
( (uint32_t) x << 16 ) ^ ( (uint32_t) z << 24 );
FT1[i] = ROTL8( FT0[i] ); FT1[i] = ROTL8(FT0[i]);
FT2[i] = ROTL8( FT1[i] ); FT2[i] = ROTL8(FT1[i]);
FT3[i] = ROTL8( FT2[i] ); FT3[i] = ROTL8(FT2[i]);
#if AES_DECRYPTION // whether AES decryption is supported #if AES_DECRYPTION // whether AES decryption is supported
x = RSb[i]; x = RSb[i];
RT0[i] = ( (uint32_t) MUL( 0x0E, x ) ) ^ RT0[i] = ((uint32_t)MUL(0x0E, x)) ^ ((uint32_t)MUL(0x09, x) << 8) ^
( (uint32_t) MUL( 0x09, x ) << 8 ) ^ ((uint32_t)MUL(0x0D, x) << 16) ^ ((uint32_t)MUL(0x0B, x) << 24);
( (uint32_t) MUL( 0x0D, x ) << 16 ) ^
( (uint32_t) MUL( 0x0B, x ) << 24 );
RT1[i] = ROTL8( RT0[i] ); RT1[i] = ROTL8(RT0[i]);
RT2[i] = ROTL8( RT1[i] ); RT2[i] = ROTL8(RT1[i]);
RT3[i] = ROTL8( RT2[i] ); RT3[i] = ROTL8(RT2[i]);
#endif /* AES_DECRYPTION */ #endif /* AES_DECRYPTION */
} }
aes_tables_inited = 1; // flag that the tables have been generated aes_tables_inited = 1; // flag that the tables have been generated
} // to permit subsequent use of the AES cipher } // to permit subsequent use of the AES cipher
/****************************************************************************** /******************************************************************************
* *
@@ -217,80 +207,72 @@ void aes_init_keygen_tables( void )
* Valid lengths are: 16, 24 or 32 bytes (128, 192, 256 bits). * Valid lengths are: 16, 24 or 32 bytes (128, 192, 256 bits).
* *
******************************************************************************/ ******************************************************************************/
int aes_set_encryption_key( aes_context *ctx, int aes_set_encryption_key(aes_context* ctx, const uchar* key, uint keysize) {
const uchar *key, uint i; // general purpose iteration local
uint keysize ) uint32_t* RK = ctx->rk; // initialize our RoundKey buffer pointer
{
uint i; // general purpose iteration local
uint32_t *RK = ctx->rk; // initialize our RoundKey buffer pointer
for( i = 0; i < (keysize >> 2); i++ ) { for(i = 0; i < (keysize >> 2); i++) {
GET_UINT32_LE( RK[i], key, i << 2 ); GET_UINT32_LE(RK[i], key, i << 2);
} }
switch( ctx->rounds ) switch(ctx->rounds) {
{ case 10:
case 10: for(i = 0; i < 10; i++, RK += 4) {
for( i = 0; i < 10; i++, RK += 4 ) { RK[4] = RK[0] ^ RCON[i] ^ ((uint32_t)FSb[(RK[3] >> 8) & 0xFF]) ^
RK[4] = RK[0] ^ RCON[i] ^ ((uint32_t)FSb[(RK[3] >> 16) & 0xFF] << 8) ^
( (uint32_t) FSb[ ( RK[3] >> 8 ) & 0xFF ] ) ^ ((uint32_t)FSb[(RK[3] >> 24) & 0xFF] << 16) ^
( (uint32_t) FSb[ ( RK[3] >> 16 ) & 0xFF ] << 8 ) ^ ((uint32_t)FSb[(RK[3]) & 0xFF] << 24);
( (uint32_t) FSb[ ( RK[3] >> 24 ) & 0xFF ] << 16 ) ^
( (uint32_t) FSb[ ( RK[3] ) & 0xFF ] << 24 );
RK[5] = RK[1] ^ RK[4]; RK[5] = RK[1] ^ RK[4];
RK[6] = RK[2] ^ RK[5]; RK[6] = RK[2] ^ RK[5];
RK[7] = RK[3] ^ RK[6]; RK[7] = RK[3] ^ RK[6];
} }
break; break;
case 12: case 12:
for( i = 0; i < 8; i++, RK += 6 ) { for(i = 0; i < 8; i++, RK += 6) {
RK[6] = RK[0] ^ RCON[i] ^ RK[6] = RK[0] ^ RCON[i] ^ ((uint32_t)FSb[(RK[5] >> 8) & 0xFF]) ^
( (uint32_t) FSb[ ( RK[5] >> 8 ) & 0xFF ] ) ^ ((uint32_t)FSb[(RK[5] >> 16) & 0xFF] << 8) ^
( (uint32_t) FSb[ ( RK[5] >> 16 ) & 0xFF ] << 8 ) ^ ((uint32_t)FSb[(RK[5] >> 24) & 0xFF] << 16) ^
( (uint32_t) FSb[ ( RK[5] >> 24 ) & 0xFF ] << 16 ) ^ ((uint32_t)FSb[(RK[5]) & 0xFF] << 24);
( (uint32_t) FSb[ ( RK[5] ) & 0xFF ] << 24 );
RK[7] = RK[1] ^ RK[6]; RK[7] = RK[1] ^ RK[6];
RK[8] = RK[2] ^ RK[7]; RK[8] = RK[2] ^ RK[7];
RK[9] = RK[3] ^ RK[8]; RK[9] = RK[3] ^ RK[8];
RK[10] = RK[4] ^ RK[9]; RK[10] = RK[4] ^ RK[9];
RK[11] = RK[5] ^ RK[10]; RK[11] = RK[5] ^ RK[10];
} }
break; break;
case 14: case 14:
for( i = 0; i < 7; i++, RK += 8 ) { for(i = 0; i < 7; i++, RK += 8) {
RK[8] = RK[0] ^ RCON[i] ^ RK[8] = RK[0] ^ RCON[i] ^ ((uint32_t)FSb[(RK[7] >> 8) & 0xFF]) ^
( (uint32_t) FSb[ ( RK[7] >> 8 ) & 0xFF ] ) ^ ((uint32_t)FSb[(RK[7] >> 16) & 0xFF] << 8) ^
( (uint32_t) FSb[ ( RK[7] >> 16 ) & 0xFF ] << 8 ) ^ ((uint32_t)FSb[(RK[7] >> 24) & 0xFF] << 16) ^
( (uint32_t) FSb[ ( RK[7] >> 24 ) & 0xFF ] << 16 ) ^ ((uint32_t)FSb[(RK[7]) & 0xFF] << 24);
( (uint32_t) FSb[ ( RK[7] ) & 0xFF ] << 24 );
RK[9] = RK[1] ^ RK[8]; RK[9] = RK[1] ^ RK[8];
RK[10] = RK[2] ^ RK[9]; RK[10] = RK[2] ^ RK[9];
RK[11] = RK[3] ^ RK[10]; RK[11] = RK[3] ^ RK[10];
RK[12] = RK[4] ^ RK[12] = RK[4] ^ ((uint32_t)FSb[(RK[11]) & 0xFF]) ^
( (uint32_t) FSb[ ( RK[11] ) & 0xFF ] ) ^ ((uint32_t)FSb[(RK[11] >> 8) & 0xFF] << 8) ^
( (uint32_t) FSb[ ( RK[11] >> 8 ) & 0xFF ] << 8 ) ^ ((uint32_t)FSb[(RK[11] >> 16) & 0xFF] << 16) ^
( (uint32_t) FSb[ ( RK[11] >> 16 ) & 0xFF ] << 16 ) ^ ((uint32_t)FSb[(RK[11] >> 24) & 0xFF] << 24);
( (uint32_t) FSb[ ( RK[11] >> 24 ) & 0xFF ] << 24 );
RK[13] = RK[5] ^ RK[12]; RK[13] = RK[5] ^ RK[12];
RK[14] = RK[6] ^ RK[13]; RK[14] = RK[6] ^ RK[13];
RK[15] = RK[7] ^ RK[14]; RK[15] = RK[7] ^ RK[14];
} }
break; break;
default: default:
return -1; return -1;
} }
return( 0 ); return (0);
} }
#if AES_DECRYPTION // whether AES decryption is supported #if AES_DECRYPTION // whether AES decryption is supported
/****************************************************************************** /******************************************************************************
* *
@@ -302,37 +284,31 @@ int aes_set_encryption_key( aes_context *ctx,
* length in bits. Valid lengths are: 128, 192, or 256 bits. * length in bits. Valid lengths are: 128, 192, or 256 bits.
* *
******************************************************************************/ ******************************************************************************/
int aes_set_decryption_key( aes_context *ctx, int aes_set_decryption_key(aes_context* ctx, const uchar* key, uint keysize) {
const uchar *key,
uint keysize )
{
int i, j; int i, j;
aes_context cty; // a calling aes context for set_encryption_key aes_context cty; // a calling aes context for set_encryption_key
uint32_t *RK = ctx->rk; // initialize our RoundKey buffer pointer uint32_t* RK = ctx->rk; // initialize our RoundKey buffer pointer
uint32_t *SK; uint32_t* SK;
int ret; int ret;
cty.rounds = ctx->rounds; // initialize our local aes context cty.rounds = ctx->rounds; // initialize our local aes context
cty.rk = cty.buf; // round count and key buf pointer cty.rk = cty.buf; // round count and key buf pointer
if (( ret = aes_set_encryption_key( &cty, key, keysize )) != 0 ) if((ret = aes_set_encryption_key(&cty, key, keysize)) != 0) return (ret);
return( ret );
SK = cty.rk + cty.rounds * 4; SK = cty.rk + cty.rounds * 4;
CPY128 // copy a 128-bit block from *SK to *RK CPY128 // copy a 128-bit block from *SK to *RK
for( i = ctx->rounds - 1, SK -= 8; i > 0; i--, SK -= 8 ) { for(i = ctx->rounds - 1, SK -= 8; i > 0; i--, SK -= 8) {
for( j = 0; j < 4; j++, SK++ ) { for(j = 0; j < 4; j++, SK++) {
*RK++ = RT0[ FSb[ ( *SK ) & 0xFF ] ] ^ *RK++ = RT0[FSb[(*SK) & 0xFF]] ^ RT1[FSb[(*SK >> 8) & 0xFF]] ^
RT1[ FSb[ ( *SK >> 8 ) & 0xFF ] ] ^ RT2[FSb[(*SK >> 16) & 0xFF]] ^ RT3[FSb[(*SK >> 24) & 0xFF]];
RT2[ FSb[ ( *SK >> 16 ) & 0xFF ] ] ^
RT3[ FSb[ ( *SK >> 24 ) & 0xFF ] ];
} }
} }
CPY128 // copy a 128-bit block from *SK to *RK CPY128 // copy a 128-bit block from *SK to *RK
memset( &cty, 0, sizeof( aes_context ) ); // clear local aes context memset(&cty, 0, sizeof(aes_context)); // clear local aes context
return( 0 ); return (0);
} }
#endif /* AES_DECRYPTION */ #endif /* AES_DECRYPTION */
@@ -344,34 +320,42 @@ int aes_set_decryption_key( aes_context *ctx,
* Invoked to establish the key schedule for subsequent encryption/decryption * Invoked to establish the key schedule for subsequent encryption/decryption
* *
******************************************************************************/ ******************************************************************************/
int aes_setkey( aes_context *ctx, // AES context provided by our caller int aes_setkey(
int mode, // ENCRYPT or DECRYPT flag aes_context* ctx, // AES context provided by our caller
const uchar *key, // pointer to the key int mode, // ENCRYPT or DECRYPT flag
uint keysize ) // key length in bytes const uchar* key, // pointer to the key
uint keysize) // key length in bytes
{ {
// since table initialization is not thread safe, we could either add // since table initialization is not thread safe, we could either add
// system-specific mutexes and init the AES key generation tables on // system-specific mutexes and init the AES key generation tables on
// demand, or ask the developer to simply call "gcm_initialize" once during // demand, or ask the developer to simply call "gcm_initialize" once during
// application startup before threading begins. That's what we choose. // application startup before threading begins. That's what we choose.
if( !aes_tables_inited ) return ( -1 ); // fail the call when not inited. if(!aes_tables_inited) return (-1); // fail the call when not inited.
ctx->mode = mode; // capture the key type we're creating ctx->mode = mode; // capture the key type we're creating
ctx->rk = ctx->buf; // initialize our round key pointer ctx->rk = ctx->buf; // initialize our round key pointer
switch( keysize ) // set the rounds count based upon the keysize switch(keysize) // set the rounds count based upon the keysize
{ {
case 16: ctx->rounds = 10; break; // 16-byte, 128-bit key case 16:
case 24: ctx->rounds = 12; break; // 24-byte, 192-bit key ctx->rounds = 10;
case 32: ctx->rounds = 14; break; // 32-byte, 256-bit key break; // 16-byte, 128-bit key
default: return(-1); case 24:
ctx->rounds = 12;
break; // 24-byte, 192-bit key
case 32:
ctx->rounds = 14;
break; // 32-byte, 256-bit key
default:
return (-1);
} }
#if AES_DECRYPTION #if AES_DECRYPTION
if( mode == DECRYPT ) // expand our key for encryption or decryption if(mode == DECRYPT) // expand our key for encryption or decryption
return( aes_set_decryption_key( ctx, key, keysize ) ); return (aes_set_decryption_key(ctx, key, keysize));
else /* ENCRYPT */ else /* ENCRYPT */
#endif /* AES_DECRYPTION */ #endif /* AES_DECRYPTION */
return( aes_set_encryption_key( ctx, key, keysize ) ); return (aes_set_encryption_key(ctx, key, keysize));
} }
/****************************************************************************** /******************************************************************************
@@ -383,101 +367,74 @@ int aes_setkey( aes_context *ctx, // AES context provided by our caller
* and all keying information appropriate for the task. * and all keying information appropriate for the task.
* *
******************************************************************************/ ******************************************************************************/
int aes_cipher( aes_context *ctx, int aes_cipher(aes_context* ctx, const uchar input[16], uchar output[16]) {
const uchar input[16],
uchar output[16] )
{
int i; int i;
uint32_t *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; // general purpose locals uint32_t *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; // general purpose locals
RK = ctx->rk; RK = ctx->rk;
GET_UINT32_LE( X0, input, 0 ); X0 ^= *RK++; // load our 128-bit GET_UINT32_LE(X0, input, 0);
GET_UINT32_LE( X1, input, 4 ); X1 ^= *RK++; // input buffer in a storage X0 ^= *RK++; // load our 128-bit
GET_UINT32_LE( X2, input, 8 ); X2 ^= *RK++; // memory endian-neutral way GET_UINT32_LE(X1, input, 4);
GET_UINT32_LE( X3, input, 12 ); X3 ^= *RK++; X1 ^= *RK++; // input buffer in a storage
GET_UINT32_LE(X2, input, 8);
X2 ^= *RK++; // memory endian-neutral way
GET_UINT32_LE(X3, input, 12);
X3 ^= *RK++;
#if AES_DECRYPTION // whether AES decryption is supported #if AES_DECRYPTION // whether AES decryption is supported
if( ctx->mode == DECRYPT ) if(ctx->mode == DECRYPT) {
{ for(i = (ctx->rounds >> 1) - 1; i > 0; i--) {
for( i = (ctx->rounds >> 1) - 1; i > 0; i-- ) AES_RROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3);
{ AES_RROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3);
AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 );
AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 );
} }
AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); AES_RROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3);
X0 = *RK++ ^ \ X0 = *RK++ ^ ((uint32_t)RSb[(Y0)&0xFF]) ^ ((uint32_t)RSb[(Y3 >> 8) & 0xFF] << 8) ^
( (uint32_t) RSb[ ( Y0 ) & 0xFF ] ) ^ ((uint32_t)RSb[(Y2 >> 16) & 0xFF] << 16) ^ ((uint32_t)RSb[(Y1 >> 24) & 0xFF] << 24);
( (uint32_t) RSb[ ( Y3 >> 8 ) & 0xFF ] << 8 ) ^
( (uint32_t) RSb[ ( Y2 >> 16 ) & 0xFF ] << 16 ) ^
( (uint32_t) RSb[ ( Y1 >> 24 ) & 0xFF ] << 24 );
X1 = *RK++ ^ \ X1 = *RK++ ^ ((uint32_t)RSb[(Y1)&0xFF]) ^ ((uint32_t)RSb[(Y0 >> 8) & 0xFF] << 8) ^
( (uint32_t) RSb[ ( Y1 ) & 0xFF ] ) ^ ((uint32_t)RSb[(Y3 >> 16) & 0xFF] << 16) ^ ((uint32_t)RSb[(Y2 >> 24) & 0xFF] << 24);
( (uint32_t) RSb[ ( Y0 >> 8 ) & 0xFF ] << 8 ) ^
( (uint32_t) RSb[ ( Y3 >> 16 ) & 0xFF ] << 16 ) ^
( (uint32_t) RSb[ ( Y2 >> 24 ) & 0xFF ] << 24 );
X2 = *RK++ ^ \ X2 = *RK++ ^ ((uint32_t)RSb[(Y2)&0xFF]) ^ ((uint32_t)RSb[(Y1 >> 8) & 0xFF] << 8) ^
( (uint32_t) RSb[ ( Y2 ) & 0xFF ] ) ^ ((uint32_t)RSb[(Y0 >> 16) & 0xFF] << 16) ^ ((uint32_t)RSb[(Y3 >> 24) & 0xFF] << 24);
( (uint32_t) RSb[ ( Y1 >> 8 ) & 0xFF ] << 8 ) ^
( (uint32_t) RSb[ ( Y0 >> 16 ) & 0xFF ] << 16 ) ^
( (uint32_t) RSb[ ( Y3 >> 24 ) & 0xFF ] << 24 );
X3 = *RK++ ^ \ X3 = *RK++ ^ ((uint32_t)RSb[(Y3)&0xFF]) ^ ((uint32_t)RSb[(Y2 >> 8) & 0xFF] << 8) ^
( (uint32_t) RSb[ ( Y3 ) & 0xFF ] ) ^ ((uint32_t)RSb[(Y1 >> 16) & 0xFF] << 16) ^ ((uint32_t)RSb[(Y0 >> 24) & 0xFF] << 24);
( (uint32_t) RSb[ ( Y2 >> 8 ) & 0xFF ] << 8 ) ^ } else /* ENCRYPT */
( (uint32_t) RSb[ ( Y1 >> 16 ) & 0xFF ] << 16 ) ^
( (uint32_t) RSb[ ( Y0 >> 24 ) & 0xFF ] << 24 );
}
else /* ENCRYPT */
{ {
#endif /* AES_DECRYPTION */ #endif /* AES_DECRYPTION */
for( i = (ctx->rounds >> 1) - 1; i > 0; i-- ) for(i = (ctx->rounds >> 1) - 1; i > 0; i--) {
{ AES_FROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3);
AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); AES_FROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3);
AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 );
} }
AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); AES_FROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3);
X0 = *RK++ ^ \ X0 = *RK++ ^ ((uint32_t)FSb[(Y0)&0xFF]) ^ ((uint32_t)FSb[(Y1 >> 8) & 0xFF] << 8) ^
( (uint32_t) FSb[ ( Y0 ) & 0xFF ] ) ^ ((uint32_t)FSb[(Y2 >> 16) & 0xFF] << 16) ^ ((uint32_t)FSb[(Y3 >> 24) & 0xFF] << 24);
( (uint32_t) FSb[ ( Y1 >> 8 ) & 0xFF ] << 8 ) ^
( (uint32_t) FSb[ ( Y2 >> 16 ) & 0xFF ] << 16 ) ^
( (uint32_t) FSb[ ( Y3 >> 24 ) & 0xFF ] << 24 );
X1 = *RK++ ^ \ X1 = *RK++ ^ ((uint32_t)FSb[(Y1)&0xFF]) ^ ((uint32_t)FSb[(Y2 >> 8) & 0xFF] << 8) ^
( (uint32_t) FSb[ ( Y1 ) & 0xFF ] ) ^ ((uint32_t)FSb[(Y3 >> 16) & 0xFF] << 16) ^ ((uint32_t)FSb[(Y0 >> 24) & 0xFF] << 24);
( (uint32_t) FSb[ ( Y2 >> 8 ) & 0xFF ] << 8 ) ^
( (uint32_t) FSb[ ( Y3 >> 16 ) & 0xFF ] << 16 ) ^
( (uint32_t) FSb[ ( Y0 >> 24 ) & 0xFF ] << 24 );
X2 = *RK++ ^ \ X2 = *RK++ ^ ((uint32_t)FSb[(Y2)&0xFF]) ^ ((uint32_t)FSb[(Y3 >> 8) & 0xFF] << 8) ^
( (uint32_t) FSb[ ( Y2 ) & 0xFF ] ) ^ ((uint32_t)FSb[(Y0 >> 16) & 0xFF] << 16) ^ ((uint32_t)FSb[(Y1 >> 24) & 0xFF] << 24);
( (uint32_t) FSb[ ( Y3 >> 8 ) & 0xFF ] << 8 ) ^
( (uint32_t) FSb[ ( Y0 >> 16 ) & 0xFF ] << 16 ) ^
( (uint32_t) FSb[ ( Y1 >> 24 ) & 0xFF ] << 24 );
X3 = *RK++ ^ \ X3 = *RK++ ^ ((uint32_t)FSb[(Y3)&0xFF]) ^ ((uint32_t)FSb[(Y0 >> 8) & 0xFF] << 8) ^
( (uint32_t) FSb[ ( Y3 ) & 0xFF ] ) ^ ((uint32_t)FSb[(Y1 >> 16) & 0xFF] << 16) ^ ((uint32_t)FSb[(Y2 >> 24) & 0xFF] << 24);
( (uint32_t) FSb[ ( Y0 >> 8 ) & 0xFF ] << 8 ) ^
( (uint32_t) FSb[ ( Y1 >> 16 ) & 0xFF ] << 16 ) ^
( (uint32_t) FSb[ ( Y2 >> 24 ) & 0xFF ] << 24 );
#if AES_DECRYPTION // whether AES decryption is supported #if AES_DECRYPTION // whether AES decryption is supported
} }
#endif /* AES_DECRYPTION */ #endif /* AES_DECRYPTION */
PUT_UINT32_LE( X0, output, 0 ); PUT_UINT32_LE(X0, output, 0);
PUT_UINT32_LE( X1, output, 4 ); PUT_UINT32_LE(X1, output, 4);
PUT_UINT32_LE( X2, output, 8 ); PUT_UINT32_LE(X2, output, 8);
PUT_UINT32_LE( X3, output, 12 ); PUT_UINT32_LE(X3, output, 12);
return( 0 ); return (0);
} }
/* end of aes.c */ /* end of aes.c */

View File

@@ -24,58 +24,57 @@
#define AES_HEADER #define AES_HEADER
/******************************************************************************/ /******************************************************************************/
#define AES_DECRYPTION 0 // whether AES decryption is supported #define AES_DECRYPTION 0 // whether AES decryption is supported
/******************************************************************************/ /******************************************************************************/
#include <string.h> #include <string.h>
#define ENCRYPT 1 // specify whether we're encrypting #define ENCRYPT 1 // specify whether we're encrypting
#define DECRYPT 0 // or decrypting #define DECRYPT 0 // or decrypting
#if defined(_MSC_VER) #if defined(_MSC_VER)
#include <basetsd.h> #include <basetsd.h>
typedef UINT32 uint32_t; typedef UINT32 uint32_t;
#else #else
#include <inttypes.h> #include <inttypes.h>
#endif #endif
typedef unsigned char uchar; // add some convienent shorter types typedef unsigned char uchar; // add some convienent shorter types
typedef unsigned int uint; typedef unsigned int uint;
/****************************************************************************** /******************************************************************************
* AES_INIT_KEYGEN_TABLES : MUST be called once before any AES use * AES_INIT_KEYGEN_TABLES : MUST be called once before any AES use
******************************************************************************/ ******************************************************************************/
void aes_init_keygen_tables( void ); void aes_init_keygen_tables(void);
/****************************************************************************** /******************************************************************************
* AES_CONTEXT : cipher context / holds inter-call data * AES_CONTEXT : cipher context / holds inter-call data
******************************************************************************/ ******************************************************************************/
typedef struct { typedef struct {
int mode; // 1 for Encryption, 0 for Decryption int mode; // 1 for Encryption, 0 for Decryption
int rounds; // keysize-based rounds count int rounds; // keysize-based rounds count
uint32_t *rk; // pointer to current round key uint32_t* rk; // pointer to current round key
uint32_t buf[68]; // key expansion buffer uint32_t buf[68]; // key expansion buffer
} aes_context; } aes_context;
/****************************************************************************** /******************************************************************************
* AES_SETKEY : called to expand the key for encryption or decryption * AES_SETKEY : called to expand the key for encryption or decryption
******************************************************************************/ ******************************************************************************/
int aes_setkey( aes_context *ctx, // pointer to context int aes_setkey(
int mode, // 1 or 0 for Encrypt/Decrypt aes_context* ctx, // pointer to context
const uchar *key, // AES input key int mode, // 1 or 0 for Encrypt/Decrypt
uint keysize ); // size in bytes (must be 16, 24, 32 for const uchar* key, // AES input key
// 128, 192 or 256-bit keys respectively) uint keysize); // size in bytes (must be 16, 24, 32 for
// returns 0 for success // 128, 192 or 256-bit keys respectively)
// returns 0 for success
/****************************************************************************** /******************************************************************************
* AES_CIPHER : called to encrypt or decrypt ONE 128-bit block of data * AES_CIPHER : called to encrypt or decrypt ONE 128-bit block of data
******************************************************************************/ ******************************************************************************/
int aes_cipher( aes_context *ctx, // pointer to context int aes_cipher(
const uchar input[16], // 128-bit block to en/decipher aes_context* ctx, // pointer to context
uchar output[16] ); // 128-bit output result block const uchar input[16], // 128-bit block to en/decipher
// returns 0 for success uchar output[16]); // 128-bit output result block
// returns 0 for success
#endif /* AES_HEADER */ #endif /* AES_HEADER */

View File

@@ -76,25 +76,40 @@
* significantly slower 128x128 bit multiple within GF(2^128). * significantly slower 128x128 bit multiple within GF(2^128).
*/ */
static const uint64_t last4[16] = { static const uint64_t last4[16] = {
0x0000, 0x1c20, 0x3840, 0x2460, 0x7080, 0x6ca0, 0x48c0, 0x54e0, 0x0000,
0xe100, 0xfd20, 0xd940, 0xc560, 0x9180, 0x8da0, 0xa9c0, 0xb5e0 }; 0x1c20,
0x3840,
0x2460,
0x7080,
0x6ca0,
0x48c0,
0x54e0,
0xe100,
0xfd20,
0xd940,
0xc560,
0x9180,
0x8da0,
0xa9c0,
0xb5e0};
/* /*
* Platform Endianness Neutralizing Load and Store Macro definitions * Platform Endianness Neutralizing Load and Store Macro definitions
* GCM wants platform-neutral Big Endian (BE) byte ordering * GCM wants platform-neutral Big Endian (BE) byte ordering
*/ */
#define GET_UINT32_BE(n,b,i) { \ #define GET_UINT32_BE(n, b, i) \
(n) = ( (uint32_t) (b)[(i) ] << 24 ) \ { \
| ( (uint32_t) (b)[(i) + 1] << 16 ) \ (n) = ((uint32_t)(b)[(i)] << 24) | ((uint32_t)(b)[(i) + 1] << 16) | \
| ( (uint32_t) (b)[(i) + 2] << 8 ) \ ((uint32_t)(b)[(i) + 2] << 8) | ((uint32_t)(b)[(i) + 3]); \
| ( (uint32_t) (b)[(i) + 3] ); } }
#define PUT_UINT32_BE(n,b,i) { \
(b)[(i) ] = (uchar) ( (n) >> 24 ); \
(b)[(i) + 1] = (uchar) ( (n) >> 16 ); \
(b)[(i) + 2] = (uchar) ( (n) >> 8 ); \
(b)[(i) + 3] = (uchar) ( (n) ); }
#define PUT_UINT32_BE(n, b, i) \
{ \
(b)[(i)] = (uchar)((n) >> 24); \
(b)[(i) + 1] = (uchar)((n) >> 16); \
(b)[(i) + 2] = (uchar)((n) >> 8); \
(b)[(i) + 3] = (uchar)((n)); \
}
/****************************************************************************** /******************************************************************************
* *
@@ -108,13 +123,11 @@ static const uint64_t last4[16] = {
* environment is running. * environment is running.
* *
******************************************************************************/ ******************************************************************************/
int gcm_initialize( void ) int gcm_initialize(void) {
{
aes_init_keygen_tables(); aes_init_keygen_tables();
return( 0 ); return (0);
} }
/****************************************************************************** /******************************************************************************
* *
* GCM_MULT * GCM_MULT
@@ -124,45 +137,45 @@ int gcm_initialize( void )
* 'x' and 'output' are seen as elements of GCM's GF(2^128) Galois field. * 'x' and 'output' are seen as elements of GCM's GF(2^128) Galois field.
* *
******************************************************************************/ ******************************************************************************/
static void gcm_mult( gcm_context *ctx, // pointer to established context static void gcm_mult(
const uchar x[16], // pointer to 128-bit input vector gcm_context* ctx, // pointer to established context
uchar output[16] ) // pointer to 128-bit output vector const uchar x[16], // pointer to 128-bit input vector
uchar output[16]) // pointer to 128-bit output vector
{ {
int i; int i;
uchar lo, hi, rem; uchar lo, hi, rem;
uint64_t zh, zl; uint64_t zh, zl;
lo = (uchar)( x[15] & 0x0f ); lo = (uchar)(x[15] & 0x0f);
hi = (uchar)( x[15] >> 4 ); hi = (uchar)(x[15] >> 4);
zh = ctx->HH[lo]; zh = ctx->HH[lo];
zl = ctx->HL[lo]; zl = ctx->HL[lo];
for( i = 15; i >= 0; i-- ) { for(i = 15; i >= 0; i--) {
lo = (uchar) ( x[i] & 0x0f ); lo = (uchar)(x[i] & 0x0f);
hi = (uchar) ( x[i] >> 4 ); hi = (uchar)(x[i] >> 4);
if( i != 15 ) { if(i != 15) {
rem = (uchar) ( zl & 0x0f ); rem = (uchar)(zl & 0x0f);
zl = ( zh << 60 ) | ( zl >> 4 ); zl = (zh << 60) | (zl >> 4);
zh = ( zh >> 4 ); zh = (zh >> 4);
zh ^= (uint64_t) last4[rem] << 48; zh ^= (uint64_t)last4[rem] << 48;
zh ^= ctx->HH[lo]; zh ^= ctx->HH[lo];
zl ^= ctx->HL[lo]; zl ^= ctx->HL[lo];
} }
rem = (uchar) ( zl & 0x0f ); rem = (uchar)(zl & 0x0f);
zl = ( zh << 60 ) | ( zl >> 4 ); zl = (zh << 60) | (zl >> 4);
zh = ( zh >> 4 ); zh = (zh >> 4);
zh ^= (uint64_t) last4[rem] << 48; zh ^= (uint64_t)last4[rem] << 48;
zh ^= ctx->HH[hi]; zh ^= ctx->HH[hi];
zl ^= ctx->HL[hi]; zl ^= ctx->HL[hi];
} }
PUT_UINT32_BE( zh >> 32, output, 0 ); PUT_UINT32_BE(zh >> 32, output, 0);
PUT_UINT32_BE( zh, output, 4 ); PUT_UINT32_BE(zh, output, 4);
PUT_UINT32_BE( zl >> 32, output, 8 ); PUT_UINT32_BE(zl >> 32, output, 8);
PUT_UINT32_BE( zl, output, 12 ); PUT_UINT32_BE(zl, output, 12);
} }
/****************************************************************************** /******************************************************************************
* *
* GCM_SETKEY * GCM_SETKEY
@@ -171,59 +184,57 @@ static void gcm_mult( gcm_context *ctx, // pointer to established context
* and populates the gcm context's pre-calculated HTables. * and populates the gcm context's pre-calculated HTables.
* *
******************************************************************************/ ******************************************************************************/
int gcm_setkey( gcm_context *ctx, // pointer to caller-provided gcm context int gcm_setkey(
const uchar *key, // pointer to the AES encryption key gcm_context* ctx, // pointer to caller-provided gcm context
const uint keysize) // size in bytes (must be 16, 24, 32 for const uchar* key, // pointer to the AES encryption key
// 128, 192 or 256-bit keys respectively) const uint keysize) // size in bytes (must be 16, 24, 32 for
// 128, 192 or 256-bit keys respectively)
{ {
int ret, i, j; int ret, i, j;
uint64_t hi, lo; uint64_t hi, lo;
uint64_t vl, vh; uint64_t vl, vh;
unsigned char h[16]; unsigned char h[16];
memset( ctx, 0, sizeof(gcm_context) ); // zero caller-provided GCM context memset(ctx, 0, sizeof(gcm_context)); // zero caller-provided GCM context
memset( h, 0, 16 ); // initialize the block to encrypt memset(h, 0, 16); // initialize the block to encrypt
// encrypt the null 128-bit block to generate a key-based value // encrypt the null 128-bit block to generate a key-based value
// which is then used to initialize our GHASH lookup tables // which is then used to initialize our GHASH lookup tables
if(( ret = aes_setkey( &ctx->aes_ctx, ENCRYPT, key, keysize )) != 0 ) if((ret = aes_setkey(&ctx->aes_ctx, ENCRYPT, key, keysize)) != 0) return (ret);
return( ret ); if((ret = aes_cipher(&ctx->aes_ctx, h, h)) != 0) return (ret);
if(( ret = aes_cipher( &ctx->aes_ctx, h, h )) != 0 )
return( ret );
GET_UINT32_BE( hi, h, 0 ); // pack h as two 64-bit ints, big-endian GET_UINT32_BE(hi, h, 0); // pack h as two 64-bit ints, big-endian
GET_UINT32_BE( lo, h, 4 ); GET_UINT32_BE(lo, h, 4);
vh = (uint64_t) hi << 32 | lo; vh = (uint64_t)hi << 32 | lo;
GET_UINT32_BE( hi, h, 8 ); GET_UINT32_BE(hi, h, 8);
GET_UINT32_BE( lo, h, 12 ); GET_UINT32_BE(lo, h, 12);
vl = (uint64_t) hi << 32 | lo; vl = (uint64_t)hi << 32 | lo;
ctx->HL[8] = vl; // 8 = 1000 corresponds to 1 in GF(2^128) ctx->HL[8] = vl; // 8 = 1000 corresponds to 1 in GF(2^128)
ctx->HH[8] = vh; ctx->HH[8] = vh;
ctx->HH[0] = 0; // 0 corresponds to 0 in GF(2^128) ctx->HH[0] = 0; // 0 corresponds to 0 in GF(2^128)
ctx->HL[0] = 0; ctx->HL[0] = 0;
for( i = 4; i > 0; i >>= 1 ) { for(i = 4; i > 0; i >>= 1) {
uint32_t T = (uint32_t) ( vl & 1 ) * 0xe1000000U; uint32_t T = (uint32_t)(vl & 1) * 0xe1000000U;
vl = ( vh << 63 ) | ( vl >> 1 ); vl = (vh << 63) | (vl >> 1);
vh = ( vh >> 1 ) ^ ( (uint64_t) T << 32); vh = (vh >> 1) ^ ((uint64_t)T << 32);
ctx->HL[i] = vl; ctx->HL[i] = vl;
ctx->HH[i] = vh; ctx->HH[i] = vh;
} }
for (i = 2; i < 16; i <<= 1 ) { for(i = 2; i < 16; i <<= 1) {
uint64_t *HiL = ctx->HL + i, *HiH = ctx->HH + i; uint64_t *HiL = ctx->HL + i, *HiH = ctx->HH + i;
vh = *HiH; vh = *HiH;
vl = *HiL; vl = *HiL;
for( j = 1; j < i; j++ ) { for(j = 1; j < i; j++) {
HiH[j] = vh ^ ctx->HH[j]; HiH[j] = vh ^ ctx->HH[j];
HiL[j] = vl ^ ctx->HL[j]; HiL[j] = vl ^ ctx->HL[j];
} }
} }
return( 0 ); return (0);
} }
/****************************************************************************** /******************************************************************************
* *
* GCM processing occurs four phases: SETKEY, START, UPDATE and FINISH. * GCM processing occurs four phases: SETKEY, START, UPDATE and FINISH.
@@ -245,62 +256,61 @@ int gcm_setkey( gcm_context *ctx, // pointer to caller-provided gcm context
* mode, and preprocesses the initialization vector and additional AEAD data. * mode, and preprocesses the initialization vector and additional AEAD data.
* *
******************************************************************************/ ******************************************************************************/
int gcm_start( gcm_context *ctx, // pointer to user-provided GCM context int gcm_start(
int mode, // GCM_ENCRYPT or GCM_DECRYPT gcm_context* ctx, // pointer to user-provided GCM context
const uchar *iv, // pointer to initialization vector int mode, // GCM_ENCRYPT or GCM_DECRYPT
size_t iv_len, // IV length in bytes (should == 12) const uchar* iv, // pointer to initialization vector
const uchar *add, // ptr to additional AEAD data (NULL if none) size_t iv_len, // IV length in bytes (should == 12)
size_t add_len ) // length of additional AEAD data (bytes) const uchar* add, // ptr to additional AEAD data (NULL if none)
size_t add_len) // length of additional AEAD data (bytes)
{ {
int ret; // our error return if the AES encrypt fails int ret; // our error return if the AES encrypt fails
uchar work_buf[16]; // XOR source built from provided IV if len != 16 uchar work_buf[16]; // XOR source built from provided IV if len != 16
const uchar *p; // general purpose array pointer const uchar* p; // general purpose array pointer
size_t use_len; // byte count to process, up to 16 bytes size_t use_len; // byte count to process, up to 16 bytes
size_t i; // local loop iterator size_t i; // local loop iterator
// since the context might be reused under the same key // since the context might be reused under the same key
// we zero the working buffers for this next new process // we zero the working buffers for this next new process
memset( ctx->y, 0x00, sizeof(ctx->y ) ); memset(ctx->y, 0x00, sizeof(ctx->y));
memset( ctx->buf, 0x00, sizeof(ctx->buf) ); memset(ctx->buf, 0x00, sizeof(ctx->buf));
ctx->len = 0; ctx->len = 0;
ctx->add_len = 0; ctx->add_len = 0;
ctx->mode = mode; // set the GCM encryption/decryption mode ctx->mode = mode; // set the GCM encryption/decryption mode
ctx->aes_ctx.mode = ENCRYPT; // GCM *always* runs AES in ENCRYPTION mode ctx->aes_ctx.mode = ENCRYPT; // GCM *always* runs AES in ENCRYPTION mode
if( iv_len == 12 ) { // GCM natively uses a 12-byte, 96-bit IV if(iv_len == 12) { // GCM natively uses a 12-byte, 96-bit IV
memcpy( ctx->y, iv, iv_len ); // copy the IV to the top of the 'y' buff memcpy(ctx->y, iv, iv_len); // copy the IV to the top of the 'y' buff
ctx->y[15] = 1; // start "counting" from 1 (not 0) ctx->y[15] = 1; // start "counting" from 1 (not 0)
} } else // if we don't have a 12-byte IV, we GHASH whatever we've been given
else // if we don't have a 12-byte IV, we GHASH whatever we've been given
{ {
memset( work_buf, 0x00, 16 ); // clear the working buffer memset(work_buf, 0x00, 16); // clear the working buffer
PUT_UINT32_BE( iv_len * 8, work_buf, 12 ); // place the IV into buffer PUT_UINT32_BE(iv_len * 8, work_buf, 12); // place the IV into buffer
p = iv; p = iv;
while( iv_len > 0 ) { while(iv_len > 0) {
use_len = ( iv_len < 16 ) ? iv_len : 16; use_len = (iv_len < 16) ? iv_len : 16;
for( i = 0; i < use_len; i++ ) ctx->y[i] ^= p[i]; for(i = 0; i < use_len; i++) ctx->y[i] ^= p[i];
gcm_mult( ctx, ctx->y, ctx->y ); gcm_mult(ctx, ctx->y, ctx->y);
iv_len -= use_len; iv_len -= use_len;
p += use_len; p += use_len;
} }
for( i = 0; i < 16; i++ ) ctx->y[i] ^= work_buf[i]; for(i = 0; i < 16; i++) ctx->y[i] ^= work_buf[i];
gcm_mult( ctx, ctx->y, ctx->y ); gcm_mult(ctx, ctx->y, ctx->y);
} }
if( ( ret = aes_cipher( &ctx->aes_ctx, ctx->y, ctx->base_ectr ) ) != 0 ) if((ret = aes_cipher(&ctx->aes_ctx, ctx->y, ctx->base_ectr)) != 0) return (ret);
return( ret );
ctx->add_len = add_len; ctx->add_len = add_len;
p = add; p = add;
while( add_len > 0 ) { while(add_len > 0) {
use_len = ( add_len < 16 ) ? add_len : 16; use_len = (add_len < 16) ? add_len : 16;
for( i = 0; i < use_len; i++ ) ctx->buf[i] ^= p[i]; for(i = 0; i < use_len; i++) ctx->buf[i] ^= p[i];
gcm_mult( ctx, ctx->buf, ctx->buf ); gcm_mult(ctx, ctx->buf, ctx->buf);
add_len -= use_len; add_len -= use_len;
p += use_len; p += use_len;
} }
return( 0 ); return (0);
} }
/****************************************************************************** /******************************************************************************
@@ -314,63 +324,61 @@ int gcm_start( gcm_context *ctx, // pointer to user-provided GCM context
* have a partial block length of < 128 bits.) * have a partial block length of < 128 bits.)
* *
******************************************************************************/ ******************************************************************************/
int gcm_update( gcm_context *ctx, // pointer to user-provided GCM context int gcm_update(
size_t length, // length, in bytes, of data to process gcm_context* ctx, // pointer to user-provided GCM context
const uchar *input, // pointer to source data size_t length, // length, in bytes, of data to process
uchar *output ) // pointer to destination data const uchar* input, // pointer to source data
uchar* output) // pointer to destination data
{ {
int ret; // our error return if the AES encrypt fails int ret; // our error return if the AES encrypt fails
uchar ectr[16]; // counter-mode cipher output for XORing uchar ectr[16]; // counter-mode cipher output for XORing
size_t use_len; // byte count to process, up to 16 bytes size_t use_len; // byte count to process, up to 16 bytes
size_t i; // local loop iterator size_t i; // local loop iterator
ctx->len += length; // bump the GCM context's running length count ctx->len += length; // bump the GCM context's running length count
while( length > 0 ) { while(length > 0) {
// clamp the length to process at 16 bytes // clamp the length to process at 16 bytes
use_len = ( length < 16 ) ? length : 16; use_len = (length < 16) ? length : 16;
// increment the context's 128-bit IV||Counter 'y' vector // increment the context's 128-bit IV||Counter 'y' vector
for( i = 16; i > 12; i-- ) if( ++ctx->y[i - 1] != 0 ) break; for(i = 16; i > 12; i--)
if(++ctx->y[i - 1] != 0) break;
// encrypt the context's 'y' vector under the established key // encrypt the context's 'y' vector under the established key
if( ( ret = aes_cipher( &ctx->aes_ctx, ctx->y, ectr ) ) != 0 ) if((ret = aes_cipher(&ctx->aes_ctx, ctx->y, ectr)) != 0) return (ret);
return( ret );
// encrypt or decrypt the input to the output // encrypt or decrypt the input to the output
if( ctx->mode == ENCRYPT ) if(ctx->mode == ENCRYPT) {
{ for(i = 0; i < use_len; i++) {
for( i = 0; i < use_len; i++ ) {
// XOR the cipher's ouptut vector (ectr) with our input // XOR the cipher's ouptut vector (ectr) with our input
output[i] = (uchar) ( ectr[i] ^ input[i] ); output[i] = (uchar)(ectr[i] ^ input[i]);
// now we mix in our data into the authentication hash. // now we mix in our data into the authentication hash.
// if we're ENcrypting we XOR in the post-XOR (output) // if we're ENcrypting we XOR in the post-XOR (output)
// results, but if we're DEcrypting we XOR in the input // results, but if we're DEcrypting we XOR in the input
// data // data
ctx->buf[i] ^= output[i]; ctx->buf[i] ^= output[i];
} }
} } else {
else for(i = 0; i < use_len; i++) {
{
for( i = 0; i < use_len; i++ ) {
// but if we're DEcrypting we XOR in the input data first, // but if we're DEcrypting we XOR in the input data first,
// i.e. before saving to ouput data, otherwise if the input // i.e. before saving to ouput data, otherwise if the input
// and output buffer are the same (inplace decryption) we // and output buffer are the same (inplace decryption) we
// would not get the correct auth tag // would not get the correct auth tag
ctx->buf[i] ^= input[i]; ctx->buf[i] ^= input[i];
// XOR the cipher's ouptut vector (ectr) with our input // XOR the cipher's ouptut vector (ectr) with our input
output[i] = (uchar) ( ectr[i] ^ input[i] ); output[i] = (uchar)(ectr[i] ^ input[i]);
} }
} }
gcm_mult( ctx, ctx->buf, ctx->buf ); // perform a GHASH operation gcm_mult(ctx, ctx->buf, ctx->buf); // perform a GHASH operation
length -= use_len; // drop the remaining byte count to process length -= use_len; // drop the remaining byte count to process
input += use_len; // bump our input pointer forward input += use_len; // bump our input pointer forward
output += use_len; // bump our output pointer forward output += use_len; // bump our output pointer forward
} }
return( 0 ); return (0);
} }
/****************************************************************************** /******************************************************************************
@@ -381,33 +389,33 @@ int gcm_update( gcm_context *ctx, // pointer to user-provided GCM context
* It performs the final GHASH to produce the resulting authentication TAG. * It performs the final GHASH to produce the resulting authentication TAG.
* *
******************************************************************************/ ******************************************************************************/
int gcm_finish( gcm_context *ctx, // pointer to user-provided GCM context int gcm_finish(
uchar *tag, // pointer to buffer which receives the tag gcm_context* ctx, // pointer to user-provided GCM context
size_t tag_len ) // length, in bytes, of the tag-receiving buf uchar* tag, // pointer to buffer which receives the tag
size_t tag_len) // length, in bytes, of the tag-receiving buf
{ {
uchar work_buf[16]; uchar work_buf[16];
uint64_t orig_len = ctx->len * 8; uint64_t orig_len = ctx->len * 8;
uint64_t orig_add_len = ctx->add_len * 8; uint64_t orig_add_len = ctx->add_len * 8;
size_t i; size_t i;
if( tag_len != 0 ) memcpy( tag, ctx->base_ectr, tag_len ); if(tag_len != 0) memcpy(tag, ctx->base_ectr, tag_len);
if( orig_len || orig_add_len ) { if(orig_len || orig_add_len) {
memset( work_buf, 0x00, 16 ); memset(work_buf, 0x00, 16);
PUT_UINT32_BE( ( orig_add_len >> 32 ), work_buf, 0 ); PUT_UINT32_BE((orig_add_len >> 32), work_buf, 0);
PUT_UINT32_BE( ( orig_add_len ), work_buf, 4 ); PUT_UINT32_BE((orig_add_len), work_buf, 4);
PUT_UINT32_BE( ( orig_len >> 32 ), work_buf, 8 ); PUT_UINT32_BE((orig_len >> 32), work_buf, 8);
PUT_UINT32_BE( ( orig_len ), work_buf, 12 ); PUT_UINT32_BE((orig_len), work_buf, 12);
for( i = 0; i < 16; i++ ) ctx->buf[i] ^= work_buf[i]; for(i = 0; i < 16; i++) ctx->buf[i] ^= work_buf[i];
gcm_mult( ctx, ctx->buf, ctx->buf ); gcm_mult(ctx, ctx->buf, ctx->buf);
for( i = 0; i < tag_len; i++ ) tag[i] ^= ctx->buf[i]; for(i = 0; i < tag_len; i++) tag[i] ^= ctx->buf[i];
} }
return( 0 ); return (0);
} }
/****************************************************************************** /******************************************************************************
* *
* GCM_CRYPT_AND_TAG * GCM_CRYPT_AND_TAG
@@ -426,29 +434,28 @@ int gcm_finish( gcm_context *ctx, // pointer to user-provided GCM context
* *
******************************************************************************/ ******************************************************************************/
int gcm_crypt_and_tag( int gcm_crypt_and_tag(
gcm_context *ctx, // gcm context with key already setup gcm_context* ctx, // gcm context with key already setup
int mode, // cipher direction: GCM_ENCRYPT or GCM_DECRYPT int mode, // cipher direction: GCM_ENCRYPT or GCM_DECRYPT
const uchar *iv, // pointer to the 12-byte initialization vector const uchar* iv, // pointer to the 12-byte initialization vector
size_t iv_len, // byte length if the IV. should always be 12 size_t iv_len, // byte length if the IV. should always be 12
const uchar *add, // pointer to the non-ciphered additional data const uchar* add, // pointer to the non-ciphered additional data
size_t add_len, // byte length of the additional AEAD data size_t add_len, // byte length of the additional AEAD data
const uchar *input, // pointer to the cipher data source const uchar* input, // pointer to the cipher data source
uchar *output, // pointer to the cipher data destination uchar* output, // pointer to the cipher data destination
size_t length, // byte length of the cipher data size_t length, // byte length of the cipher data
uchar *tag, // pointer to the tag to be generated uchar* tag, // pointer to the tag to be generated
size_t tag_len ) // byte length of the tag to be generated size_t tag_len) // byte length of the tag to be generated
{ /* { /*
assuming that the caller has already invoked gcm_setkey to assuming that the caller has already invoked gcm_setkey to
prepare the gcm context with the keying material, we simply prepare the gcm context with the keying material, we simply
invoke each of the three GCM sub-functions in turn... invoke each of the three GCM sub-functions in turn...
*/ */
gcm_start ( ctx, mode, iv, iv_len, add, add_len ); gcm_start(ctx, mode, iv, iv_len, add, add_len);
gcm_update ( ctx, length, input, output ); gcm_update(ctx, length, input, output);
gcm_finish ( ctx, tag, tag_len ); gcm_finish(ctx, tag, tag_len);
return( 0 ); return (0);
} }
/****************************************************************************** /******************************************************************************
* *
* GCM_AUTH_DECRYPT * GCM_AUTH_DECRYPT
@@ -462,37 +469,36 @@ int gcm_crypt_and_tag(
* *
******************************************************************************/ ******************************************************************************/
int gcm_auth_decrypt( int gcm_auth_decrypt(
gcm_context *ctx, // gcm context with key already setup gcm_context* ctx, // gcm context with key already setup
const uchar *iv, // pointer to the 12-byte initialization vector const uchar* iv, // pointer to the 12-byte initialization vector
size_t iv_len, // byte length if the IV. should always be 12 size_t iv_len, // byte length if the IV. should always be 12
const uchar *add, // pointer to the non-ciphered additional data const uchar* add, // pointer to the non-ciphered additional data
size_t add_len, // byte length of the additional AEAD data size_t add_len, // byte length of the additional AEAD data
const uchar *input, // pointer to the cipher data source const uchar* input, // pointer to the cipher data source
uchar *output, // pointer to the cipher data destination uchar* output, // pointer to the cipher data destination
size_t length, // byte length of the cipher data size_t length, // byte length of the cipher data
const uchar *tag, // pointer to the tag to be authenticated const uchar* tag, // pointer to the tag to be authenticated
size_t tag_len ) // byte length of the tag <= 16 size_t tag_len) // byte length of the tag <= 16
{ {
uchar check_tag[16]; // the tag generated and returned by decryption uchar check_tag[16]; // the tag generated and returned by decryption
int diff; // an ORed flag to detect authentication errors int diff; // an ORed flag to detect authentication errors
size_t i; // our local iterator size_t i; // our local iterator
/* /*
we use GCM_DECRYPT_AND_TAG (above) to perform our decryption we use GCM_DECRYPT_AND_TAG (above) to perform our decryption
(which is an identical XORing to reverse the previous one) (which is an identical XORing to reverse the previous one)
and also to re-generate the matching authentication tag and also to re-generate the matching authentication tag
*/ */
gcm_crypt_and_tag( ctx, DECRYPT, iv, iv_len, add, add_len, gcm_crypt_and_tag(
input, output, length, check_tag, tag_len ); ctx, DECRYPT, iv, iv_len, add, add_len, input, output, length, check_tag, tag_len);
// now we verify the authentication tag in 'constant time' // now we verify the authentication tag in 'constant time'
for( diff = 0, i = 0; i < tag_len; i++ ) for(diff = 0, i = 0; i < tag_len; i++) diff |= tag[i] ^ check_tag[i];
diff |= tag[i] ^ check_tag[i];
if( diff != 0 ) { // see whether any bits differed? if(diff != 0) { // see whether any bits differed?
memset( output, 0, length ); // if so... wipe the output data memset(output, 0, length); // if so... wipe the output data
return( GCM_AUTH_FAILURE ); // return GCM_AUTH_FAILURE return (GCM_AUTH_FAILURE); // return GCM_AUTH_FAILURE
} }
return( 0 ); return (0);
} }
/****************************************************************************** /******************************************************************************
@@ -504,8 +510,7 @@ int gcm_auth_decrypt(
* sensitive, so it MUST be zeroed after use. This function does that. * sensitive, so it MUST be zeroed after use. This function does that.
* *
******************************************************************************/ ******************************************************************************/
void gcm_zero_ctx( gcm_context *ctx ) void gcm_zero_ctx(gcm_context* ctx) {
{
// zero the context originally provided to us // zero the context originally provided to us
memset( ctx, 0, sizeof( gcm_context ) ); memset(ctx, 0, sizeof(gcm_context));
} }

View File

@@ -24,52 +24,49 @@
#ifndef GCM_HEADER #ifndef GCM_HEADER
#define GCM_HEADER #define GCM_HEADER
#define GCM_AUTH_FAILURE 0x55555555 // authentication failure #define GCM_AUTH_FAILURE 0x55555555 // authentication failure
#include "aes.h" // gcm_context includes aes_context #include "aes.h" // gcm_context includes aes_context
#if defined(_MSC_VER) #if defined(_MSC_VER)
#include <basetsd.h> #include <basetsd.h>
typedef unsigned int size_t;// use the right type for length declarations typedef unsigned int size_t; // use the right type for length declarations
typedef UINT32 uint32_t; typedef UINT32 uint32_t;
typedef UINT64 uint64_t; typedef UINT64 uint64_t;
#else #else
#include <stdint.h> #include <stdint.h>
#endif #endif
/****************************************************************************** /******************************************************************************
* GCM_CONTEXT : GCM context / holds keytables, instance data, and AES ctx * GCM_CONTEXT : GCM context / holds keytables, instance data, and AES ctx
******************************************************************************/ ******************************************************************************/
typedef struct { typedef struct {
int mode; // cipher direction: encrypt/decrypt int mode; // cipher direction: encrypt/decrypt
uint64_t len; // cipher data length processed so far uint64_t len; // cipher data length processed so far
uint64_t add_len; // total add data length uint64_t add_len; // total add data length
uint64_t HL[16]; // precalculated lo-half HTable uint64_t HL[16]; // precalculated lo-half HTable
uint64_t HH[16]; // precalculated hi-half HTable uint64_t HH[16]; // precalculated hi-half HTable
uchar base_ectr[16]; // first counter-mode cipher output for tag uchar base_ectr[16]; // first counter-mode cipher output for tag
uchar y[16]; // the current cipher-input IV|Counter value uchar y[16]; // the current cipher-input IV|Counter value
uchar buf[16]; // buf working value uchar buf[16]; // buf working value
aes_context aes_ctx; // cipher context used aes_context aes_ctx; // cipher context used
} gcm_context; } gcm_context;
/****************************************************************************** /******************************************************************************
* GCM_CONTEXT : MUST be called once before ANY use of this library * GCM_CONTEXT : MUST be called once before ANY use of this library
******************************************************************************/ ******************************************************************************/
int gcm_initialize( void ); int gcm_initialize(void);
/****************************************************************************** /******************************************************************************
* GCM_SETKEY : sets the GCM (and AES) keying material for use * GCM_SETKEY : sets the GCM (and AES) keying material for use
******************************************************************************/ ******************************************************************************/
int gcm_setkey( gcm_context *ctx, // caller-provided context ptr int gcm_setkey(
const uchar *key, // pointer to cipher key gcm_context* ctx, // caller-provided context ptr
const uint keysize // size in bytes (must be 16, 24, 32 for const uchar* key, // pointer to cipher key
// 128, 192 or 256-bit keys respectively) const uint keysize // size in bytes (must be 16, 24, 32 for
// 128, 192 or 256-bit keys respectively)
); // returns 0 for success ); // returns 0 for success
/****************************************************************************** /******************************************************************************
* *
* GCM_CRYPT_AND_TAG * GCM_CRYPT_AND_TAG
@@ -88,18 +85,17 @@ int gcm_setkey( gcm_context *ctx, // caller-provided context ptr
* *
******************************************************************************/ ******************************************************************************/
int gcm_crypt_and_tag( int gcm_crypt_and_tag(
gcm_context *ctx, // gcm context with key already setup gcm_context* ctx, // gcm context with key already setup
int mode, // cipher direction: ENCRYPT (1) or DECRYPT (0) int mode, // cipher direction: ENCRYPT (1) or DECRYPT (0)
const uchar *iv, // pointer to the 12-byte initialization vector const uchar* iv, // pointer to the 12-byte initialization vector
size_t iv_len, // byte length if the IV. should always be 12 size_t iv_len, // byte length if the IV. should always be 12
const uchar *add, // pointer to the non-ciphered additional data const uchar* add, // pointer to the non-ciphered additional data
size_t add_len, // byte length of the additional AEAD data size_t add_len, // byte length of the additional AEAD data
const uchar *input, // pointer to the cipher data source const uchar* input, // pointer to the cipher data source
uchar *output, // pointer to the cipher data destination uchar* output, // pointer to the cipher data destination
size_t length, // byte length of the cipher data size_t length, // byte length of the cipher data
uchar *tag, // pointer to the tag to be generated uchar* tag, // pointer to the tag to be generated
size_t tag_len ); // byte length of the tag to be generated size_t tag_len); // byte length of the tag to be generated
/****************************************************************************** /******************************************************************************
* *
@@ -114,17 +110,16 @@ int gcm_crypt_and_tag(
* *
******************************************************************************/ ******************************************************************************/
int gcm_auth_decrypt( int gcm_auth_decrypt(
gcm_context *ctx, // gcm context with key already setup gcm_context* ctx, // gcm context with key already setup
const uchar *iv, // pointer to the 12-byte initialization vector const uchar* iv, // pointer to the 12-byte initialization vector
size_t iv_len, // byte length if the IV. should always be 12 size_t iv_len, // byte length if the IV. should always be 12
const uchar *add, // pointer to the non-ciphered additional data const uchar* add, // pointer to the non-ciphered additional data
size_t add_len, // byte length of the additional AEAD data size_t add_len, // byte length of the additional AEAD data
const uchar *input, // pointer to the cipher data source const uchar* input, // pointer to the cipher data source
uchar *output, // pointer to the cipher data destination uchar* output, // pointer to the cipher data destination
size_t length, // byte length of the cipher data size_t length, // byte length of the cipher data
const uchar *tag, // pointer to the tag to be authenticated const uchar* tag, // pointer to the tag to be authenticated
size_t tag_len ); // byte length of the tag <= 16 size_t tag_len); // byte length of the tag <= 16
/****************************************************************************** /******************************************************************************
* *
@@ -134,13 +129,13 @@ int gcm_auth_decrypt(
* mode, and preprocesses the initialization vector and additional AEAD data. * mode, and preprocesses the initialization vector and additional AEAD data.
* *
******************************************************************************/ ******************************************************************************/
int gcm_start( gcm_context *ctx, // pointer to user-provided GCM context int gcm_start(
int mode, // ENCRYPT (1) or DECRYPT (0) gcm_context* ctx, // pointer to user-provided GCM context
const uchar *iv, // pointer to initialization vector int mode, // ENCRYPT (1) or DECRYPT (0)
size_t iv_len, // IV length in bytes (should == 12) const uchar* iv, // pointer to initialization vector
const uchar *add, // pointer to additional AEAD data (NULL if none) size_t iv_len, // IV length in bytes (should == 12)
size_t add_len ); // length of additional AEAD data (bytes) const uchar* add, // pointer to additional AEAD data (NULL if none)
size_t add_len); // length of additional AEAD data (bytes)
/****************************************************************************** /******************************************************************************
* *
@@ -153,11 +148,11 @@ int gcm_start( gcm_context *ctx, // pointer to user-provided GCM context
* have a partial block length of < 128 bits.) * have a partial block length of < 128 bits.)
* *
******************************************************************************/ ******************************************************************************/
int gcm_update( gcm_context *ctx, // pointer to user-provided GCM context int gcm_update(
size_t length, // length, in bytes, of data to process gcm_context* ctx, // pointer to user-provided GCM context
const uchar *input, // pointer to source data size_t length, // length, in bytes, of data to process
uchar *output ); // pointer to destination data const uchar* input, // pointer to source data
uchar* output); // pointer to destination data
/****************************************************************************** /******************************************************************************
* *
@@ -167,10 +162,10 @@ int gcm_update( gcm_context *ctx, // pointer to user-provided GCM context
* It performs the final GHASH to produce the resulting authentication TAG. * It performs the final GHASH to produce the resulting authentication TAG.
* *
******************************************************************************/ ******************************************************************************/
int gcm_finish( gcm_context *ctx, // pointer to user-provided GCM context int gcm_finish(
uchar *tag, // ptr to tag buffer - NULL if tag_len = 0 gcm_context* ctx, // pointer to user-provided GCM context
size_t tag_len ); // length, in bytes, of the tag-receiving buf uchar* tag, // ptr to tag buffer - NULL if tag_len = 0
size_t tag_len); // length, in bytes, of the tag-receiving buf
/****************************************************************************** /******************************************************************************
* *
@@ -181,7 +176,6 @@ int gcm_finish( gcm_context *ctx, // pointer to user-provided GCM context
* sensitive, so it MUST be zeroed after use. This function does that. * sensitive, so it MUST be zeroed after use. This function does that.
* *
******************************************************************************/ ******************************************************************************/
void gcm_zero_ctx( gcm_context *ctx ); void gcm_zero_ctx(gcm_context* ctx);
#endif /* GCM_HEADER */ #endif /* GCM_HEADER */

View File

@@ -11,181 +11,191 @@
DICT_DEF2(ESubGhzChatReplayDict, uint64_t, uint32_t) DICT_DEF2(ESubGhzChatReplayDict, uint64_t, uint32_t)
struct ESugGhzChatCryptoCtx { struct ESugGhzChatCryptoCtx {
uint8_t key[KEY_BITS / 8]; uint8_t key[KEY_BITS / 8];
#ifndef FURI_HAL_CRYPTO_ADVANCED_AVAIL #ifndef FURI_HAL_CRYPTO_ADVANCED_AVAIL
gcm_context gcm_ctx; gcm_context gcm_ctx;
#endif /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */ #endif /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
ESubGhzChatReplayDict_t replay_dict; ESubGhzChatReplayDict_t replay_dict;
uint64_t run_id; uint64_t run_id;
uint32_t counter; uint32_t counter;
}; };
struct ESubGhzChatCryptoMsg { struct ESubGhzChatCryptoMsg {
uint64_t run_id; uint64_t run_id;
uint32_t counter; uint32_t counter;
uint8_t iv[IV_BYTES]; uint8_t iv[IV_BYTES];
uint8_t tag[TAG_BYTES]; uint8_t tag[TAG_BYTES];
uint8_t data[0]; uint8_t data[0];
} __attribute__ ((packed)); } __attribute__((packed));
void crypto_init(void) void crypto_init(void) {
{
#ifndef FURI_HAL_CRYPTO_ADVANCED_AVAIL #ifndef FURI_HAL_CRYPTO_ADVANCED_AVAIL
/* init the GCM and AES tables */ /* init the GCM and AES tables */
gcm_initialize(); gcm_initialize();
#endif /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */ #endif /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
} }
void crypto_explicit_bzero(void *s, size_t len) void crypto_explicit_bzero(void* s, size_t len) {
{ memset(s, 0, len);
memset(s, 0, len); asm volatile("" ::: "memory");
asm volatile("" ::: "memory");
} }
ESubGhzChatCryptoCtx *crypto_ctx_alloc(void) ESubGhzChatCryptoCtx* crypto_ctx_alloc(void) {
{ ESubGhzChatCryptoCtx* ret = malloc(sizeof(ESubGhzChatCryptoCtx));
ESubGhzChatCryptoCtx *ret = malloc(sizeof(ESubGhzChatCryptoCtx));
if (ret != NULL) { if(ret != NULL) {
memset(ret, 0, sizeof(ESubGhzChatCryptoCtx)); memset(ret, 0, sizeof(ESubGhzChatCryptoCtx));
ESubGhzChatReplayDict_init(ret->replay_dict); ESubGhzChatReplayDict_init(ret->replay_dict);
ret->run_id = 0; ret->run_id = 0;
ret->counter = 1; ret->counter = 1;
} }
return ret; return ret;
} }
void crypto_ctx_free(ESubGhzChatCryptoCtx *ctx) void crypto_ctx_free(ESubGhzChatCryptoCtx* ctx) {
{ crypto_ctx_clear(ctx);
crypto_ctx_clear(ctx); ESubGhzChatReplayDict_clear(ctx->replay_dict);
ESubGhzChatReplayDict_clear(ctx->replay_dict); free(ctx);
free(ctx);
} }
void crypto_ctx_clear(ESubGhzChatCryptoCtx *ctx) void crypto_ctx_clear(ESubGhzChatCryptoCtx* ctx) {
{ crypto_explicit_bzero(ctx->key, sizeof(ctx->key));
crypto_explicit_bzero(ctx->key, sizeof(ctx->key));
#ifndef FURI_HAL_CRYPTO_ADVANCED_AVAIL #ifndef FURI_HAL_CRYPTO_ADVANCED_AVAIL
crypto_explicit_bzero(&(ctx->gcm_ctx), sizeof(ctx->gcm_ctx)); crypto_explicit_bzero(&(ctx->gcm_ctx), sizeof(ctx->gcm_ctx));
#endif /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */ #endif /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
ESubGhzChatReplayDict_reset(ctx->replay_dict); ESubGhzChatReplayDict_reset(ctx->replay_dict);
ctx->run_id = 0; ctx->run_id = 0;
ctx->counter = 1; ctx->counter = 1;
} }
static uint64_t crypto_calc_run_id(FuriString *flipper_name, uint32_t tick) static uint64_t crypto_calc_run_id(FuriString* flipper_name, uint32_t tick) {
{ const char* fn = furi_string_get_cstr(flipper_name);
const char *fn = furi_string_get_cstr(flipper_name); size_t fn_len = strlen(fn);
size_t fn_len = strlen(fn);
uint8_t h_in[fn_len + sizeof(uint32_t)]; uint8_t h_in[fn_len + sizeof(uint32_t)];
memcpy(h_in, fn, fn_len); memcpy(h_in, fn, fn_len);
memcpy(h_in + fn_len, &tick, sizeof(uint32_t)); memcpy(h_in + fn_len, &tick, sizeof(uint32_t));
uint8_t h_out[256]; uint8_t h_out[256];
sha256(h_in, fn_len + sizeof(uint32_t), h_out); sha256(h_in, fn_len + sizeof(uint32_t), h_out);
uint64_t run_id; uint64_t run_id;
memcpy(&run_id, h_out, sizeof(uint64_t)); memcpy(&run_id, h_out, sizeof(uint64_t));
return run_id; return run_id;
} }
bool crypto_ctx_set_key(ESubGhzChatCryptoCtx *ctx, const uint8_t *key, bool crypto_ctx_set_key(
FuriString *flipper_name, uint32_t tick) ESubGhzChatCryptoCtx* ctx,
{ const uint8_t* key,
ctx->run_id = crypto_calc_run_id(flipper_name, tick); FuriString* flipper_name,
ctx->counter = 1; uint32_t tick) {
ctx->run_id = crypto_calc_run_id(flipper_name, tick);
ctx->counter = 1;
memcpy(ctx->key, key, KEY_BITS / 8); memcpy(ctx->key, key, KEY_BITS / 8);
#ifdef FURI_HAL_CRYPTO_ADVANCED_AVAIL #ifdef FURI_HAL_CRYPTO_ADVANCED_AVAIL
return true; return true;
#else /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */ #else /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
return (gcm_setkey(&(ctx->gcm_ctx), key, KEY_BITS / 8) == 0); return (gcm_setkey(&(ctx->gcm_ctx), key, KEY_BITS / 8) == 0);
#endif /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */ #endif /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
} }
void crypto_ctx_get_key(ESubGhzChatCryptoCtx *ctx, uint8_t *key) void crypto_ctx_get_key(ESubGhzChatCryptoCtx* ctx, uint8_t* key) {
{ memcpy(key, ctx->key, KEY_BITS / 8);
memcpy(key, ctx->key, KEY_BITS / 8);
} }
bool crypto_ctx_decrypt(ESubGhzChatCryptoCtx *ctx, uint8_t *in, size_t in_len, bool crypto_ctx_decrypt(ESubGhzChatCryptoCtx* ctx, uint8_t* in, size_t in_len, uint8_t* out) {
uint8_t *out) if(in_len < MSG_OVERHEAD + 1) {
{ return false;
if (in_len < MSG_OVERHEAD + 1) { }
return false;
}
struct ESubGhzChatCryptoMsg *msg = (struct ESubGhzChatCryptoMsg *) in; struct ESubGhzChatCryptoMsg* msg = (struct ESubGhzChatCryptoMsg*)in;
// check if message is stale, if yes, discard // check if message is stale, if yes, discard
uint32_t *counter = ESubGhzChatReplayDict_get(ctx->replay_dict, uint32_t* counter = ESubGhzChatReplayDict_get(ctx->replay_dict, msg->run_id);
msg->run_id); if(counter != NULL) {
if (counter != NULL) { if(*counter >= __ntohl(msg->counter)) {
if (*counter >= __ntohl(msg->counter)) { return false;
return false; }
} }
}
// decrypt and auth message // decrypt and auth message
#ifdef FURI_HAL_CRYPTO_ADVANCED_AVAIL #ifdef FURI_HAL_CRYPTO_ADVANCED_AVAIL
bool ret = (furi_hal_crypto_gcm_decrypt_and_verify(ctx->key, bool ret =
msg->iv, (furi_hal_crypto_gcm_decrypt_and_verify(
(uint8_t *) msg, RUN_ID_BYTES + COUNTER_BYTES, ctx->key,
msg->data, out, msg->iv,
in_len - MSG_OVERHEAD, (uint8_t*)msg,
msg->tag) == FuriHalCryptoGCMStateOk); RUN_ID_BYTES + COUNTER_BYTES,
msg->data,
out,
in_len - MSG_OVERHEAD,
msg->tag) == FuriHalCryptoGCMStateOk);
#else /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */ #else /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
bool ret = (gcm_auth_decrypt(&(ctx->gcm_ctx), bool ret =
msg->iv, IV_BYTES, (gcm_auth_decrypt(
(uint8_t *) msg, RUN_ID_BYTES + COUNTER_BYTES, &(ctx->gcm_ctx),
msg->data, out, msg->iv,
in_len - MSG_OVERHEAD, IV_BYTES,
msg->tag, TAG_BYTES) == 0); (uint8_t*)msg,
RUN_ID_BYTES + COUNTER_BYTES,
msg->data,
out,
in_len - MSG_OVERHEAD,
msg->tag,
TAG_BYTES) == 0);
#endif /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */ #endif /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
// if auth was successful update replay dict // if auth was successful update replay dict
if (ret) { if(ret) {
ESubGhzChatReplayDict_set_at(ctx->replay_dict, msg->run_id, ESubGhzChatReplayDict_set_at(ctx->replay_dict, msg->run_id, __ntohl(msg->counter));
__ntohl(msg->counter)); }
}
return ret; return ret;
} }
bool crypto_ctx_encrypt(ESubGhzChatCryptoCtx *ctx, uint8_t *in, size_t in_len, bool crypto_ctx_encrypt(ESubGhzChatCryptoCtx* ctx, uint8_t* in, size_t in_len, uint8_t* out) {
uint8_t *out) struct ESubGhzChatCryptoMsg* msg = (struct ESubGhzChatCryptoMsg*)out;
{
struct ESubGhzChatCryptoMsg *msg = (struct ESubGhzChatCryptoMsg *) out;
// fill message header // fill message header
msg->run_id = ctx->run_id; msg->run_id = ctx->run_id;
msg->counter = __htonl(ctx->counter); msg->counter = __htonl(ctx->counter);
furi_hal_random_fill_buf(msg->iv, IV_BYTES); furi_hal_random_fill_buf(msg->iv, IV_BYTES);
// encrypt message and store tag in header // encrypt message and store tag in header
#ifdef FURI_HAL_CRYPTO_ADVANCED_AVAIL #ifdef FURI_HAL_CRYPTO_ADVANCED_AVAIL
bool ret = (furi_hal_crypto_gcm_encrypt_and_tag(ctx->key, bool ret =
msg->iv, (furi_hal_crypto_gcm_encrypt_and_tag(
(uint8_t *) msg, RUN_ID_BYTES + COUNTER_BYTES, ctx->key,
in, msg->data, msg->iv,
in_len, (uint8_t*)msg,
msg->tag) == FuriHalCryptoGCMStateOk); RUN_ID_BYTES + COUNTER_BYTES,
in,
msg->data,
in_len,
msg->tag) == FuriHalCryptoGCMStateOk);
#else /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */ #else /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
bool ret = (gcm_crypt_and_tag(&(ctx->gcm_ctx), ENCRYPT, bool ret =
msg->iv, IV_BYTES, (gcm_crypt_and_tag(
(uint8_t *) msg, RUN_ID_BYTES + COUNTER_BYTES, &(ctx->gcm_ctx),
in, msg->data, ENCRYPT,
in_len, msg->iv,
msg->tag, TAG_BYTES) == 0); IV_BYTES,
(uint8_t*)msg,
RUN_ID_BYTES + COUNTER_BYTES,
in,
msg->data,
in_len,
msg->tag,
TAG_BYTES) == 0);
#endif /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */ #endif /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
// increase internal counter // increase internal counter
if (ret) { if(ret) {
ctx->counter++; ctx->counter++;
} }
return ret; return ret;
} }

View File

@@ -17,21 +17,22 @@ typedef struct ESugGhzChatCryptoCtx ESubGhzChatCryptoCtx;
void crypto_init(void); void crypto_init(void);
/* Function to clear sensitive memory. */ /* Function to clear sensitive memory. */
void crypto_explicit_bzero(void *s, size_t len); void crypto_explicit_bzero(void* s, size_t len);
ESubGhzChatCryptoCtx *crypto_ctx_alloc(void); ESubGhzChatCryptoCtx* crypto_ctx_alloc(void);
void crypto_ctx_free(ESubGhzChatCryptoCtx *ctx); void crypto_ctx_free(ESubGhzChatCryptoCtx* ctx);
void crypto_ctx_clear(ESubGhzChatCryptoCtx *ctx); void crypto_ctx_clear(ESubGhzChatCryptoCtx* ctx);
bool crypto_ctx_set_key(ESubGhzChatCryptoCtx *ctx, const uint8_t *key, bool crypto_ctx_set_key(
FuriString *flipper_name, uint32_t tick); ESubGhzChatCryptoCtx* ctx,
void crypto_ctx_get_key(ESubGhzChatCryptoCtx *ctx, uint8_t *key); const uint8_t* key,
FuriString* flipper_name,
uint32_t tick);
void crypto_ctx_get_key(ESubGhzChatCryptoCtx* ctx, uint8_t* key);
bool crypto_ctx_decrypt(ESubGhzChatCryptoCtx *ctx, uint8_t *in, size_t in_len, bool crypto_ctx_decrypt(ESubGhzChatCryptoCtx* ctx, uint8_t* in, size_t in_len, uint8_t* out);
uint8_t *out); bool crypto_ctx_encrypt(ESubGhzChatCryptoCtx* ctx, uint8_t* in, size_t in_len, uint8_t* out);
bool crypto_ctx_encrypt(ESubGhzChatCryptoCtx *ctx, uint8_t *in, size_t in_len,
uint8_t *out);
#ifdef __cplusplus #ifdef __cplusplus
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,65 +1,59 @@
#include "../esubghz_chat_i.h" #include "../esubghz_chat_i.h"
/* Prepares the text box scene. */ /* Prepares the text box scene. */
void scene_on_enter_chat_box(void* context) void scene_on_enter_chat_box(void* context) {
{ FURI_LOG_T(APPLICATION_NAME, "scene_on_enter_chat_box");
FURI_LOG_T(APPLICATION_NAME, "scene_on_enter_chat_box");
furi_assert(context); furi_assert(context);
ESubGhzChatState* state = context; ESubGhzChatState* state = context;
text_box_reset(state->chat_box); text_box_reset(state->chat_box);
text_box_set_text(state->chat_box, text_box_set_text(state->chat_box, furi_string_get_cstr(state->chat_box_store));
furi_string_get_cstr(state->chat_box_store)); text_box_set_focus(state->chat_box, TextBoxFocusEnd);
text_box_set_focus(state->chat_box, TextBoxFocusEnd);
view_dispatcher_switch_to_view(state->view_dispatcher, ESubGhzChatView_ChatBox); view_dispatcher_switch_to_view(state->view_dispatcher, ESubGhzChatView_ChatBox);
} }
/* Handles scene manager events for the text box scene. */ /* Handles scene manager events for the text box scene. */
bool scene_on_event_chat_box(void* context, SceneManagerEvent event) bool scene_on_event_chat_box(void* context, SceneManagerEvent event) {
{ FURI_LOG_T(APPLICATION_NAME, "scene_on_event_chat_box");
FURI_LOG_T(APPLICATION_NAME, "scene_on_event_chat_box");
furi_assert(context); furi_assert(context);
ESubGhzChatState* state = context; ESubGhzChatState* state = context;
bool consumed = false; bool consumed = false;
switch(event.type) { switch(event.type) {
case SceneManagerEventTypeCustom: case SceneManagerEventTypeCustom:
switch(event.event) { switch(event.event) {
/* switch to message input scene */ /* switch to message input scene */
case ESubGhzChatEvent_GotoMsgInput: case ESubGhzChatEvent_GotoMsgInput:
if (!scene_manager_previous_scene( if(!scene_manager_previous_scene(state->scene_manager)) {
state->scene_manager)) { view_dispatcher_stop(state->view_dispatcher);
view_dispatcher_stop(state->view_dispatcher); }
} consumed = true;
consumed = true; break;
break; case ESubGhzChatEvent_GotoKeyDisplay:
case ESubGhzChatEvent_GotoKeyDisplay: scene_manager_next_scene(state->scene_manager, ESubGhzChatScene_KeyDisplay);
scene_manager_next_scene(state->scene_manager, consumed = true;
ESubGhzChatScene_KeyDisplay); break;
consumed = true; }
break; break;
}
break;
default: default:
consumed = false; consumed = false;
break; break;
} }
return consumed; return consumed;
} }
/* Cleans up the text box scene. */ /* Cleans up the text box scene. */
void scene_on_exit_chat_box(void* context) void scene_on_exit_chat_box(void* context) {
{ FURI_LOG_T(APPLICATION_NAME, "scene_on_exit_chat_box");
FURI_LOG_T(APPLICATION_NAME, "scene_on_exit_chat_box");
furi_assert(context); furi_assert(context);
ESubGhzChatState* state = context; ESubGhzChatState* state = context;
text_box_reset(state->chat_box); text_box_reset(state->chat_box);
} }

View File

@@ -6,113 +6,102 @@
* then copied into the TX buffer. The contents of the TX buffer are then * then copied into the TX buffer. The contents of the TX buffer are then
* transmitted. The sent message is appended to the text box and a MsgEntered * transmitted. The sent message is appended to the text box and a MsgEntered
* event is sent to the scene manager to switch to the text box view. */ * event is sent to the scene manager to switch to the text box view. */
static bool chat_input_validator(const char *text, FuriString *error, static bool chat_input_validator(const char* text, FuriString* error, void* context) {
void *context) UNUSED(error);
{
UNUSED(error);
furi_assert(context); furi_assert(context);
ESubGhzChatState* state = context; ESubGhzChatState* state = context;
/* no message, just switch to the text box view */ /* no message, just switch to the text box view */
if (strlen(text) == 0) { if(strlen(text) == 0) {
view_dispatcher_send_custom_event(state->view_dispatcher, view_dispatcher_send_custom_event(state->view_dispatcher, ESubGhzChatEvent_MsgEntered);
ESubGhzChatEvent_MsgEntered); return true;
return true; }
}
/* concatenate the name prefix and the actual message */ /* concatenate the name prefix and the actual message */
furi_string_set(state->msg_input, state->name_prefix); furi_string_set(state->msg_input, state->name_prefix);
furi_string_cat_str(state->msg_input, ": "); furi_string_cat_str(state->msg_input, ": ");
furi_string_cat_str(state->msg_input, text); furi_string_cat_str(state->msg_input, text);
/* append the message to the chat box and prepare message preview */ /* append the message to the chat box and prepare message preview */
append_msg(state, furi_string_get_cstr(state->msg_input)); append_msg(state, furi_string_get_cstr(state->msg_input));
/* encrypt and transmit message */ /* encrypt and transmit message */
tx_msg_input(state); tx_msg_input(state);
/* clear message input buffer */ /* clear message input buffer */
furi_string_set_char(state->msg_input, 0, 0); furi_string_set_char(state->msg_input, 0, 0);
/* switch to text box view */ /* switch to text box view */
view_dispatcher_send_custom_event(state->view_dispatcher, view_dispatcher_send_custom_event(state->view_dispatcher, ESubGhzChatEvent_MsgEntered);
ESubGhzChatEvent_MsgEntered);
return true; return true;
} }
/* Prepares the message input scene. */ /* Prepares the message input scene. */
void scene_on_enter_chat_input(void* context) void scene_on_enter_chat_input(void* context) {
{ FURI_LOG_T(APPLICATION_NAME, "scene_on_enter_chat_input");
FURI_LOG_T(APPLICATION_NAME, "scene_on_enter_chat_input");
furi_assert(context); furi_assert(context);
ESubGhzChatState* state = context; ESubGhzChatState* state = context;
state->text_input_store[0] = 0; state->text_input_store[0] = 0;
text_input_reset(state->text_input); text_input_reset(state->text_input);
/* use validator for scene change to get around minimum length /* use validator for scene change to get around minimum length
* requirement */ * requirement */
text_input_set_result_callback( text_input_set_result_callback(
state->text_input, state->text_input,
NULL, NULL,
NULL, NULL,
state->text_input_store, state->text_input_store,
sizeof(state->text_input_store), sizeof(state->text_input_store),
true); true);
text_input_set_validator( text_input_set_validator(state->text_input, chat_input_validator, state);
state->text_input, set_chat_input_header(state);
chat_input_validator,
state);
set_chat_input_header(state);
view_dispatcher_switch_to_view(state->view_dispatcher, ESubGhzChatView_Input); view_dispatcher_switch_to_view(state->view_dispatcher, ESubGhzChatView_Input);
} }
/* Handles scene manager events for the message input scene. */ /* Handles scene manager events for the message input scene. */
bool scene_on_event_chat_input(void* context, SceneManagerEvent event) bool scene_on_event_chat_input(void* context, SceneManagerEvent event) {
{ FURI_LOG_T(APPLICATION_NAME, "scene_on_event_chat_input");
FURI_LOG_T(APPLICATION_NAME, "scene_on_event_chat_input");
furi_assert(context); furi_assert(context);
ESubGhzChatState* state = context; ESubGhzChatState* state = context;
bool consumed = false; bool consumed = false;
switch(event.type) { switch(event.type) {
case SceneManagerEventTypeCustom: case SceneManagerEventTypeCustom:
switch(event.event) { switch(event.event) {
/* switch to text box scene */ /* switch to text box scene */
case ESubGhzChatEvent_MsgEntered: case ESubGhzChatEvent_MsgEntered:
scene_manager_next_scene(state->scene_manager, scene_manager_next_scene(state->scene_manager, ESubGhzChatScene_ChatBox);
ESubGhzChatScene_ChatBox); consumed = true;
consumed = true; break;
break; }
} break;
break;
case SceneManagerEventTypeBack: case SceneManagerEventTypeBack:
/* stop the application if the user presses back here */ /* stop the application if the user presses back here */
view_dispatcher_stop(state->view_dispatcher); view_dispatcher_stop(state->view_dispatcher);
consumed = true; consumed = true;
break; break;
default: default:
consumed = false; consumed = false;
break; break;
} }
return consumed; return consumed;
} }
/* Cleans up the password input scene. */ /* Cleans up the password input scene. */
void scene_on_exit_chat_input(void* context) void scene_on_exit_chat_input(void* context) {
{ FURI_LOG_T(APPLICATION_NAME, "scene_on_exit_chat_input");
FURI_LOG_T(APPLICATION_NAME, "scene_on_exit_chat_input");
furi_assert(context); furi_assert(context);
ESubGhzChatState* state = context; ESubGhzChatState* state = context;
text_input_reset(state->text_input); text_input_reset(state->text_input);
} }

View File

@@ -2,126 +2,108 @@
/* Sends FreqEntered event to scene manager and displays the frequency in the /* Sends FreqEntered event to scene manager and displays the frequency in the
* text box. */ * text box. */
static void freq_input_cb(void *context) static void freq_input_cb(void* context) {
{ furi_assert(context);
furi_assert(context); ESubGhzChatState* state = context;
ESubGhzChatState* state = context;
furi_string_cat_printf(state->chat_box_store, "Frequency: %lu", furi_string_cat_printf(state->chat_box_store, "Frequency: %lu", state->frequency);
state->frequency);
view_dispatcher_send_custom_event(state->view_dispatcher, view_dispatcher_send_custom_event(state->view_dispatcher, ESubGhzChatEvent_FreqEntered);
ESubGhzChatEvent_FreqEntered);
} }
/* Validates the entered frequency. */ /* Validates the entered frequency. */
static bool freq_input_validator(const char *text, FuriString *error, static bool freq_input_validator(const char* text, FuriString* error, void* context) {
void *context) furi_assert(text);
{ furi_assert(error);
furi_assert(text);
furi_assert(error);
furi_assert(context); furi_assert(context);
ESubGhzChatState* state = context; ESubGhzChatState* state = context;
int ret = sscanf(text, "%lu", &(state->frequency)); int ret = sscanf(text, "%lu", &(state->frequency));
if (ret != 1) { if(ret != 1) {
furi_string_printf(error, "Please enter\nfrequency\nin Hz!"); furi_string_printf(error, "Please enter\nfrequency\nin Hz!");
return false; return false;
} }
if (!subghz_devices_is_frequency_valid(state->subghz_device, if(!subghz_devices_is_frequency_valid(state->subghz_device, state->frequency)) {
state->frequency)) { furi_string_printf(error, "Frequency\n%lu\n is invalid!", state->frequency);
furi_string_printf(error, "Frequency\n%lu\n is invalid!", return false;
state->frequency); }
return false;
}
#ifdef FW_ORIGIN_Official #ifdef FW_ORIGIN_Official
if (!furi_hal_region_is_frequency_allowed(state->frequency)) { if(!furi_hal_region_is_frequency_allowed(state->frequency)) {
#else /* FW_ORIGIN_Official */ #else /* FW_ORIGIN_Official */
if (!furi_hal_subghz_is_tx_allowed(state->frequency)) { if(!furi_hal_subghz_is_tx_allowed(state->frequency)) {
#endif /* FW_ORIGIN_Official */ #endif /* FW_ORIGIN_Official */
furi_string_printf(error, "TX forbidden\non frequency\n%lu!", furi_string_printf(error, "TX forbidden\non frequency\n%lu!", state->frequency);
state->frequency); return false;
return false; }
}
return true; return true;
} }
/* Prepares the frequency input scene. */ /* Prepares the frequency input scene. */
void scene_on_enter_freq_input(void* context) void scene_on_enter_freq_input(void* context) {
{ FURI_LOG_T(APPLICATION_NAME, "scene_on_enter_freq_input");
FURI_LOG_T(APPLICATION_NAME, "scene_on_enter_freq_input");
furi_assert(context); furi_assert(context);
ESubGhzChatState* state = context; ESubGhzChatState* state = context;
snprintf(state->text_input_store, TEXT_INPUT_STORE_SIZE, "%lu", snprintf(state->text_input_store, TEXT_INPUT_STORE_SIZE, "%lu", (uint32_t)DEFAULT_FREQ);
(uint32_t) DEFAULT_FREQ); text_input_reset(state->text_input);
text_input_reset(state->text_input); text_input_set_result_callback(
text_input_set_result_callback( state->text_input,
state->text_input, freq_input_cb,
freq_input_cb, state,
state, state->text_input_store,
state->text_input_store, sizeof(state->text_input_store),
sizeof(state->text_input_store), true);
true); text_input_set_validator(state->text_input, freq_input_validator, state);
text_input_set_validator( text_input_set_header_text(state->text_input, "Frequency");
state->text_input,
freq_input_validator,
state);
text_input_set_header_text(
state->text_input,
"Frequency");
view_dispatcher_switch_to_view(state->view_dispatcher, ESubGhzChatView_Input); view_dispatcher_switch_to_view(state->view_dispatcher, ESubGhzChatView_Input);
} }
/* Handles scene manager events for the frequency input scene. */ /* Handles scene manager events for the frequency input scene. */
bool scene_on_event_freq_input(void* context, SceneManagerEvent event) bool scene_on_event_freq_input(void* context, SceneManagerEvent event) {
{ FURI_LOG_T(APPLICATION_NAME, "scene_on_event_freq_input");
FURI_LOG_T(APPLICATION_NAME, "scene_on_event_freq_input");
furi_assert(context); furi_assert(context);
ESubGhzChatState* state = context; ESubGhzChatState* state = context;
bool consumed = false; bool consumed = false;
switch(event.type) { switch(event.type) {
case SceneManagerEventTypeCustom: case SceneManagerEventTypeCustom:
switch(event.event) { switch(event.event) {
/* switch to password input scene */ /* switch to password input scene */
case ESubGhzChatEvent_FreqEntered: case ESubGhzChatEvent_FreqEntered:
scene_manager_next_scene(state->scene_manager, scene_manager_next_scene(state->scene_manager, ESubGhzChatScene_KeyMenu);
ESubGhzChatScene_KeyMenu); consumed = true;
consumed = true; break;
break; }
} break;
break;
case SceneManagerEventTypeBack: case SceneManagerEventTypeBack:
/* stop the application if the user presses back here */ /* stop the application if the user presses back here */
view_dispatcher_stop(state->view_dispatcher); view_dispatcher_stop(state->view_dispatcher);
consumed = true; consumed = true;
break; break;
default: default:
consumed = false; consumed = false;
break; break;
} }
return consumed; return consumed;
} }
/* Cleans up the frequency input scene. */ /* Cleans up the frequency input scene. */
void scene_on_exit_freq_input(void* context) void scene_on_exit_freq_input(void* context) {
{ FURI_LOG_T(APPLICATION_NAME, "scene_on_exit_freq_input");
FURI_LOG_T(APPLICATION_NAME, "scene_on_exit_freq_input");
furi_assert(context); furi_assert(context);
ESubGhzChatState* state = context; ESubGhzChatState* state = context;
text_input_reset(state->text_input); text_input_reset(state->text_input);
} }

View File

@@ -2,90 +2,81 @@
/* Sets the entered bytes as the key, enters the chat and sends a HexKeyEntered /* Sets the entered bytes as the key, enters the chat and sends a HexKeyEntered
* event to the scene manager. */ * event to the scene manager. */
static void hex_key_input_cb(void* context) static void hex_key_input_cb(void* context) {
{ furi_assert(context);
furi_assert(context); ESubGhzChatState* state = context;
ESubGhzChatState* state = context;
/* initiate the crypto context */ /* initiate the crypto context */
bool ret = crypto_ctx_set_key(state->crypto_ctx, bool ret = crypto_ctx_set_key(
state->hex_key_input_store, state->name_prefix, state->crypto_ctx, state->hex_key_input_store, state->name_prefix, furi_get_tick());
furi_get_tick());
/* cleanup */ /* cleanup */
crypto_explicit_bzero(state->hex_key_input_store, crypto_explicit_bzero(state->hex_key_input_store, sizeof(state->hex_key_input_store));
sizeof(state->hex_key_input_store));
if (!ret) { if(!ret) {
crypto_ctx_clear(state->crypto_ctx); crypto_ctx_clear(state->crypto_ctx);
return; return;
} }
state->encrypted = true; state->encrypted = true;
enter_chat(state); enter_chat(state);
view_dispatcher_send_custom_event(state->view_dispatcher, view_dispatcher_send_custom_event(state->view_dispatcher, ESubGhzChatEvent_HexKeyEntered);
ESubGhzChatEvent_HexKeyEntered);
} }
/* Prepares the hex key input scene. */ /* Prepares the hex key input scene. */
void scene_on_enter_hex_key_input(void* context) void scene_on_enter_hex_key_input(void* context) {
{ FURI_LOG_T(APPLICATION_NAME, "scene_on_enter_hex_key_input");
FURI_LOG_T(APPLICATION_NAME, "scene_on_enter_hex_key_input");
furi_assert(context); furi_assert(context);
ESubGhzChatState* state = context; ESubGhzChatState* state = context;
byte_input_set_result_callback(state->hex_key_input, byte_input_set_result_callback(
hex_key_input_cb, state->hex_key_input,
NULL, hex_key_input_cb,
state, NULL,
state->hex_key_input_store, state,
sizeof(state->hex_key_input_store)); state->hex_key_input_store,
sizeof(state->hex_key_input_store));
view_dispatcher_switch_to_view(state->view_dispatcher, view_dispatcher_switch_to_view(state->view_dispatcher, ESubGhzChatView_HexKeyInput);
ESubGhzChatView_HexKeyInput);
} }
/* Handles scene manager events for the hex key input scene. */ /* Handles scene manager events for the hex key input scene. */
bool scene_on_event_hex_key_input(void* context, SceneManagerEvent event) bool scene_on_event_hex_key_input(void* context, SceneManagerEvent event) {
{ FURI_LOG_T(APPLICATION_NAME, "scene_on_event_hex_key_input");
FURI_LOG_T(APPLICATION_NAME, "scene_on_event_hex_key_input");
furi_assert(context); furi_assert(context);
ESubGhzChatState* state = context; ESubGhzChatState* state = context;
bool consumed = false; bool consumed = false;
switch(event.type) { switch(event.type) {
case SceneManagerEventTypeCustom: case SceneManagerEventTypeCustom:
switch(event.event) { switch(event.event) {
/* switch to message input scene */ /* switch to message input scene */
case ESubGhzChatEvent_HexKeyEntered: case ESubGhzChatEvent_HexKeyEntered:
scene_manager_next_scene(state->scene_manager, scene_manager_next_scene(state->scene_manager, ESubGhzChatScene_ChatInput);
ESubGhzChatScene_ChatInput); consumed = true;
consumed = true; break;
break; }
} break;
break;
default: default:
consumed = false; consumed = false;
break; break;
} }
return consumed; return consumed;
} }
/* Cleans up the hex key input scene. */ /* Cleans up the hex key input scene. */
void scene_on_exit_hex_key_input(void* context) void scene_on_exit_hex_key_input(void* context) {
{ FURI_LOG_T(APPLICATION_NAME, "scene_on_exit_hex_key_input");
FURI_LOG_T(APPLICATION_NAME, "scene_on_exit_hex_key_input");
furi_assert(context); furi_assert(context);
ESubGhzChatState* state = context; ESubGhzChatState* state = context;
crypto_explicit_bzero(state->hex_key_input_store, crypto_explicit_bzero(state->hex_key_input_store, sizeof(state->hex_key_input_store));
sizeof(state->hex_key_input_store));
} }

View File

@@ -1,128 +1,145 @@
#include "../esubghz_chat_i.h" #include "../esubghz_chat_i.h"
void key_display_result_cb(DialogExResult result, void* context) void key_display_result_cb(DialogExResult result, void* context) {
{ furi_assert(context);
furi_assert(context); ESubGhzChatState* state = context;
ESubGhzChatState* state = context;
switch(result) { switch(result) {
case DialogExResultLeft: case DialogExResultLeft:
view_dispatcher_send_custom_event(state->view_dispatcher, view_dispatcher_send_custom_event(state->view_dispatcher, ESubGhzChatEvent_KeyDisplayBack);
ESubGhzChatEvent_KeyDisplayBack); break;
break;
case DialogExResultCenter: case DialogExResultCenter:
if (state->encrypted) { if(state->encrypted) {
view_dispatcher_send_custom_event(state->view_dispatcher, view_dispatcher_send_custom_event(
ESubGhzChatEvent_KeyDisplayShare); state->view_dispatcher, ESubGhzChatEvent_KeyDisplayShare);
} }
break; break;
default: default:
break; break;
} }
} }
/* Prepares the key display scene. */ /* Prepares the key display scene. */
void scene_on_enter_key_display(void* context) void scene_on_enter_key_display(void* context) {
{ FURI_LOG_T(APPLICATION_NAME, "scene_on_enter_key_display");
FURI_LOG_T(APPLICATION_NAME, "scene_on_enter_key_display");
furi_assert(context); furi_assert(context);
ESubGhzChatState* state = context; ESubGhzChatState* state = context;
if (state->encrypted) { if(state->encrypted) {
uint8_t key[KEY_BITS / 8]; uint8_t key[KEY_BITS / 8];
crypto_ctx_get_key(state->crypto_ctx, key); crypto_ctx_get_key(state->crypto_ctx, key);
snprintf(state->key_hex_str, KEY_HEX_STR_SIZE, snprintf(
"%02hX%02hX%02hX%02hX" state->key_hex_str,
"%02hX%02hX%02hX%02hX\n" KEY_HEX_STR_SIZE,
"%02hX%02hX%02hX%02hX" "%02hX%02hX%02hX%02hX"
"%02hX%02hX%02hX%02hX\n" "%02hX%02hX%02hX%02hX\n"
"%02hX%02hX%02hX%02hX" "%02hX%02hX%02hX%02hX"
"%02hX%02hX%02hX%02hX\n" "%02hX%02hX%02hX%02hX\n"
"%02hX%02hX%02hX%02hX" "%02hX%02hX%02hX%02hX"
"%02hX%02hX%02hX%02hX", "%02hX%02hX%02hX%02hX\n"
key[0], key[1], key[2], key[3], "%02hX%02hX%02hX%02hX"
key[4], key[5], key[6], key[7], "%02hX%02hX%02hX%02hX",
key[8], key[9], key[10], key[11], key[0],
key[12], key[13], key[14], key[15], key[1],
key[16], key[17], key[18], key[19], key[2],
key[20], key[21], key[22], key[23], key[3],
key[24], key[25], key[26], key[27], key[4],
key[28], key[29], key[30], key[31]); key[5],
crypto_explicit_bzero(key, sizeof(key)); key[6],
} else { key[7],
strcpy(state->key_hex_str, "No Key"); key[8],
} key[9],
key[10],
key[11],
key[12],
key[13],
key[14],
key[15],
key[16],
key[17],
key[18],
key[19],
key[20],
key[21],
key[22],
key[23],
key[24],
key[25],
key[26],
key[27],
key[28],
key[29],
key[30],
key[31]);
crypto_explicit_bzero(key, sizeof(key));
} else {
strcpy(state->key_hex_str, "No Key");
}
dialog_ex_reset(state->key_display); dialog_ex_reset(state->key_display);
dialog_ex_set_text(state->key_display, state->key_hex_str, 64, 2, dialog_ex_set_text(state->key_display, state->key_hex_str, 64, 2, AlignCenter, AlignTop);
AlignCenter, AlignTop);
dialog_ex_set_icon(state->key_display, 0, 0, NULL); dialog_ex_set_icon(state->key_display, 0, 0, NULL);
dialog_ex_set_left_button_text(state->key_display, "Back"); dialog_ex_set_left_button_text(state->key_display, "Back");
if (state->encrypted) { if(state->encrypted) {
dialog_ex_set_center_button_text(state->key_display, "Share"); dialog_ex_set_center_button_text(state->key_display, "Share");
} }
dialog_ex_set_result_callback(state->key_display, dialog_ex_set_result_callback(state->key_display, key_display_result_cb);
key_display_result_cb); dialog_ex_set_context(state->key_display, state);
dialog_ex_set_context(state->key_display, state);
view_dispatcher_switch_to_view(state->view_dispatcher, ESubGhzChatView_KeyDisplay); view_dispatcher_switch_to_view(state->view_dispatcher, ESubGhzChatView_KeyDisplay);
} }
/* Handles scene manager events for the key display scene. */ /* Handles scene manager events for the key display scene. */
bool scene_on_event_key_display(void* context, SceneManagerEvent event) bool scene_on_event_key_display(void* context, SceneManagerEvent event) {
{ FURI_LOG_T(APPLICATION_NAME, "scene_on_event_key_display");
FURI_LOG_T(APPLICATION_NAME, "scene_on_event_key_display");
furi_assert(context); furi_assert(context);
ESubGhzChatState* state = context; ESubGhzChatState* state = context;
bool consumed = false; bool consumed = false;
switch(event.type) { switch(event.type) {
case SceneManagerEventTypeCustom: case SceneManagerEventTypeCustom:
switch(event.event) { switch(event.event) {
/* switch to message input scene */ /* switch to message input scene */
case ESubGhzChatEvent_KeyDisplayBack: case ESubGhzChatEvent_KeyDisplayBack:
if (!scene_manager_previous_scene( if(!scene_manager_previous_scene(state->scene_manager)) {
state->scene_manager)) { view_dispatcher_stop(state->view_dispatcher);
view_dispatcher_stop(state->view_dispatcher); }
} consumed = true;
consumed = true; break;
break;
/* open key sharing popup */ /* open key sharing popup */
case ESubGhzChatEvent_KeyDisplayShare: case ESubGhzChatEvent_KeyDisplayShare:
scene_manager_next_scene(state->scene_manager, scene_manager_next_scene(state->scene_manager, ESubGhzChatScene_KeySharePopup);
ESubGhzChatScene_KeySharePopup); consumed = true;
consumed = true; break;
break; }
} break;
break;
default: default:
consumed = false; consumed = false;
break; break;
} }
return consumed; return consumed;
} }
/* Cleans up the key display scene. */ /* Cleans up the key display scene. */
void scene_on_exit_key_display(void* context) void scene_on_exit_key_display(void* context) {
{ FURI_LOG_T(APPLICATION_NAME, "scene_on_exit_key_display");
FURI_LOG_T(APPLICATION_NAME, "scene_on_exit_key_display");
furi_assert(context); furi_assert(context);
ESubGhzChatState* state = context; ESubGhzChatState* state = context;
dialog_ex_reset(state->key_display); dialog_ex_reset(state->key_display);
crypto_explicit_bzero(state->key_hex_str, sizeof(state->key_hex_str)); crypto_explicit_bzero(state->key_hex_str, sizeof(state->key_hex_str));
} }

View File

@@ -1,194 +1,162 @@
#include "../esubghz_chat_i.h" #include "../esubghz_chat_i.h"
typedef enum { typedef enum {
ESubGhzChatKeyMenuItems_NoEncryption, ESubGhzChatKeyMenuItems_NoEncryption,
ESubGhzChatKeyMenuItems_Password, ESubGhzChatKeyMenuItems_Password,
ESubGhzChatKeyMenuItems_HexKey, ESubGhzChatKeyMenuItems_HexKey,
ESubGhzChatKeyMenuItems_GenKey, ESubGhzChatKeyMenuItems_GenKey,
ESubGhzChatKeyMenuItems_ReadKeyFromNfc, ESubGhzChatKeyMenuItems_ReadKeyFromNfc,
} ESubGhzChatKeyMenuItems; } ESubGhzChatKeyMenuItems;
static void key_menu_cb(void* context, uint32_t index) static void key_menu_cb(void* context, uint32_t index) {
{ furi_assert(context);
furi_assert(context); ESubGhzChatState* state = context;
ESubGhzChatState* state = context;
uint8_t key[KEY_BITS / 8]; uint8_t key[KEY_BITS / 8];
switch(index) { switch(index) {
case ESubGhzChatKeyMenuItems_NoEncryption: case ESubGhzChatKeyMenuItems_NoEncryption:
state->encrypted = false; state->encrypted = false;
enter_chat(state); enter_chat(state);
view_dispatcher_send_custom_event(state->view_dispatcher, view_dispatcher_send_custom_event(
ESubGhzChatEvent_KeyMenuNoEncryption); state->view_dispatcher, ESubGhzChatEvent_KeyMenuNoEncryption);
break; break;
case ESubGhzChatKeyMenuItems_Password: case ESubGhzChatKeyMenuItems_Password:
view_dispatcher_send_custom_event(state->view_dispatcher, view_dispatcher_send_custom_event(
ESubGhzChatEvent_KeyMenuPassword); state->view_dispatcher, ESubGhzChatEvent_KeyMenuPassword);
break; break;
case ESubGhzChatKeyMenuItems_HexKey: case ESubGhzChatKeyMenuItems_HexKey:
view_dispatcher_send_custom_event(state->view_dispatcher, view_dispatcher_send_custom_event(state->view_dispatcher, ESubGhzChatEvent_KeyMenuHexKey);
ESubGhzChatEvent_KeyMenuHexKey); break;
break;
case ESubGhzChatKeyMenuItems_GenKey: case ESubGhzChatKeyMenuItems_GenKey:
/* generate a random key */ /* generate a random key */
furi_hal_random_fill_buf(key, KEY_BITS / 8); furi_hal_random_fill_buf(key, KEY_BITS / 8);
/* initiate the crypto context */ /* initiate the crypto context */
bool ret = crypto_ctx_set_key(state->crypto_ctx, key, bool ret = crypto_ctx_set_key(state->crypto_ctx, key, state->name_prefix, furi_get_tick());
state->name_prefix, furi_get_tick());
/* cleanup */ /* cleanup */
crypto_explicit_bzero(key, sizeof(key)); crypto_explicit_bzero(key, sizeof(key));
if (!ret) { if(!ret) {
crypto_ctx_clear(state->crypto_ctx); crypto_ctx_clear(state->crypto_ctx);
return; return;
} }
/* set encrypted flag and enter the chat */ /* set encrypted flag and enter the chat */
state->encrypted = true; state->encrypted = true;
enter_chat(state); enter_chat(state);
view_dispatcher_send_custom_event(state->view_dispatcher, view_dispatcher_send_custom_event(state->view_dispatcher, ESubGhzChatEvent_KeyMenuGenKey);
ESubGhzChatEvent_KeyMenuGenKey); break;
break;
case ESubGhzChatKeyMenuItems_ReadKeyFromNfc: case ESubGhzChatKeyMenuItems_ReadKeyFromNfc:
view_dispatcher_send_custom_event(state->view_dispatcher, view_dispatcher_send_custom_event(
ESubGhzChatEvent_KeyMenuReadKeyFromNfc); state->view_dispatcher, ESubGhzChatEvent_KeyMenuReadKeyFromNfc);
break; break;
default: default:
break; break;
} }
} }
/* Prepares the key menu scene. */ /* Prepares the key menu scene. */
void scene_on_enter_key_menu(void* context) void scene_on_enter_key_menu(void* context) {
{ FURI_LOG_T(APPLICATION_NAME, "scene_on_enter_key_menu");
FURI_LOG_T(APPLICATION_NAME, "scene_on_enter_key_menu");
furi_assert(context); furi_assert(context);
ESubGhzChatState* state = context; ESubGhzChatState* state = context;
menu_reset(state->menu); menu_reset(state->menu);
menu_add_item( menu_add_item(
state->menu, state->menu,
"No encryption", "No encryption",
NULL, NULL,
ESubGhzChatKeyMenuItems_NoEncryption, ESubGhzChatKeyMenuItems_NoEncryption,
key_menu_cb, key_menu_cb,
state state);
); menu_add_item(
menu_add_item( state->menu, "Password", NULL, ESubGhzChatKeyMenuItems_Password, key_menu_cb, state);
state->menu, menu_add_item(
"Password", state->menu, "Hex Key", NULL, ESubGhzChatKeyMenuItems_HexKey, key_menu_cb, state);
NULL, menu_add_item(
ESubGhzChatKeyMenuItems_Password, state->menu, "Generate Key", NULL, ESubGhzChatKeyMenuItems_GenKey, key_menu_cb, state);
key_menu_cb, menu_add_item(
state state->menu,
); "Read Key from NFC",
menu_add_item( NULL,
state->menu, ESubGhzChatKeyMenuItems_ReadKeyFromNfc,
"Hex Key", key_menu_cb,
NULL, state);
ESubGhzChatKeyMenuItems_HexKey,
key_menu_cb,
state
);
menu_add_item(
state->menu,
"Generate Key",
NULL,
ESubGhzChatKeyMenuItems_GenKey,
key_menu_cb,
state
);
menu_add_item(
state->menu,
"Read Key from NFC",
NULL,
ESubGhzChatKeyMenuItems_ReadKeyFromNfc,
key_menu_cb,
state
);
view_dispatcher_switch_to_view(state->view_dispatcher, ESubGhzChatView_Menu); view_dispatcher_switch_to_view(state->view_dispatcher, ESubGhzChatView_Menu);
} }
/* Handles scene manager events for the key menu scene. */ /* Handles scene manager events for the key menu scene. */
bool scene_on_event_key_menu(void* context, SceneManagerEvent event) bool scene_on_event_key_menu(void* context, SceneManagerEvent event) {
{ FURI_LOG_T(APPLICATION_NAME, "scene_on_event_key_menu");
FURI_LOG_T(APPLICATION_NAME, "scene_on_event_key_menu");
furi_assert(context); furi_assert(context);
ESubGhzChatState* state = context; ESubGhzChatState* state = context;
bool consumed = false; bool consumed = false;
switch(event.type) { switch(event.type) {
case SceneManagerEventTypeCustom: case SceneManagerEventTypeCustom:
switch(event.event) { switch(event.event) {
/* switch to message input scene */ /* switch to message input scene */
case ESubGhzChatEvent_KeyMenuNoEncryption: case ESubGhzChatEvent_KeyMenuNoEncryption:
case ESubGhzChatEvent_KeyMenuGenKey: case ESubGhzChatEvent_KeyMenuGenKey:
scene_manager_next_scene(state->scene_manager, scene_manager_next_scene(state->scene_manager, ESubGhzChatScene_ChatInput);
ESubGhzChatScene_ChatInput); consumed = true;
consumed = true; break;
break;
/* switch to password input scene */ /* switch to password input scene */
case ESubGhzChatEvent_KeyMenuPassword: case ESubGhzChatEvent_KeyMenuPassword:
scene_manager_next_scene(state->scene_manager, scene_manager_next_scene(state->scene_manager, ESubGhzChatScene_PassInput);
ESubGhzChatScene_PassInput); consumed = true;
consumed = true; break;
break;
/* switch to hex key input scene */ /* switch to hex key input scene */
case ESubGhzChatEvent_KeyMenuHexKey: case ESubGhzChatEvent_KeyMenuHexKey:
scene_manager_next_scene(state->scene_manager, scene_manager_next_scene(state->scene_manager, ESubGhzChatScene_HexKeyInput);
ESubGhzChatScene_HexKeyInput); consumed = true;
consumed = true; break;
break;
/* switch to hex key read scene */ /* switch to hex key read scene */
case ESubGhzChatEvent_KeyMenuReadKeyFromNfc: case ESubGhzChatEvent_KeyMenuReadKeyFromNfc:
scene_manager_next_scene(state->scene_manager, scene_manager_next_scene(state->scene_manager, ESubGhzChatScene_KeyReadPopup);
ESubGhzChatScene_KeyReadPopup); consumed = true;
consumed = true; break;
break; }
}
break; break;
case SceneManagerEventTypeBack: case SceneManagerEventTypeBack:
/* stop the application if the user presses back here */ /* stop the application if the user presses back here */
view_dispatcher_stop(state->view_dispatcher); view_dispatcher_stop(state->view_dispatcher);
consumed = true; consumed = true;
break; break;
default: default:
consumed = false; consumed = false;
break; break;
} }
return consumed; return consumed;
} }
/* Cleans up the key menu scene. */ /* Cleans up the key menu scene. */
void scene_on_exit_key_menu(void* context) void scene_on_exit_key_menu(void* context) {
{ FURI_LOG_T(APPLICATION_NAME, "scene_on_exit_key_menu");
FURI_LOG_T(APPLICATION_NAME, "scene_on_exit_key_menu");
furi_assert(context); furi_assert(context);
ESubGhzChatState* state = context; ESubGhzChatState* state = context;
menu_reset(state->menu); menu_reset(state->menu);
} }

View File

@@ -1,251 +1,229 @@
#include "../esubghz_chat_i.h" #include "../esubghz_chat_i.h"
typedef enum { typedef enum {
KeyReadPopupState_Idle, KeyReadPopupState_Idle,
KeyReadPopupState_Detecting, KeyReadPopupState_Detecting,
KeyReadPopupState_Reading, KeyReadPopupState_Reading,
KeyReadPopupState_Fail, KeyReadPopupState_Fail,
KeyReadPopupState_Success, KeyReadPopupState_Success,
} KeyReadPopupState; } KeyReadPopupState;
static bool read_worker_cb(NfcWorkerEvent event, void* context) static bool read_worker_cb(NfcWorkerEvent event, void* context) {
{ furi_assert(context);
furi_assert(context); ESubGhzChatState* state = context;
ESubGhzChatState* state = context;
view_dispatcher_send_custom_event(state->view_dispatcher, event); view_dispatcher_send_custom_event(state->view_dispatcher, event);
return true; return true;
} }
static void key_read_popup_timeout_cb(void* context) static void key_read_popup_timeout_cb(void* context) {
{ furi_assert(context);
furi_assert(context); ESubGhzChatState* state = context;
ESubGhzChatState* state = context;
uint32_t cur_state = scene_manager_get_scene_state( uint32_t cur_state =
state->scene_manager, ESubGhzChatScene_KeyReadPopup); scene_manager_get_scene_state(state->scene_manager, ESubGhzChatScene_KeyReadPopup);
/* done displaying our failure */ /* done displaying our failure */
if (cur_state == KeyReadPopupState_Fail) { if(cur_state == KeyReadPopupState_Fail) {
view_dispatcher_send_custom_event(state->view_dispatcher, view_dispatcher_send_custom_event(
ESubGhzChatEvent_KeyReadPopupFailed); state->view_dispatcher, ESubGhzChatEvent_KeyReadPopupFailed);
/* done displaying our success, enter chat */ /* done displaying our success, enter chat */
} else if (cur_state == KeyReadPopupState_Success) { } else if(cur_state == KeyReadPopupState_Success) {
enter_chat(state); enter_chat(state);
view_dispatcher_send_custom_event(state->view_dispatcher, view_dispatcher_send_custom_event(
ESubGhzChatEvent_KeyReadPopupSucceeded); state->view_dispatcher, ESubGhzChatEvent_KeyReadPopupSucceeded);
} }
} }
static bool key_read_popup_handle_key_read(ESubGhzChatState *state) static bool key_read_popup_handle_key_read(ESubGhzChatState* state) {
{ NfcDeviceData* dev_data = state->nfc_dev_data;
NfcDeviceData *dev_data = state->nfc_dev_data;
if (dev_data->mf_ul_data.data_read < KEY_BITS / 8) { if(dev_data->mf_ul_data.data_read < KEY_BITS / 8) {
return false; return false;
} }
/* initiate the crypto context */ /* initiate the crypto context */
bool ret = crypto_ctx_set_key(state->crypto_ctx, bool ret = crypto_ctx_set_key(
dev_data->mf_ul_data.data, state->name_prefix, state->crypto_ctx, dev_data->mf_ul_data.data, state->name_prefix, furi_get_tick());
furi_get_tick());
/* cleanup */ /* cleanup */
crypto_explicit_bzero(dev_data->mf_ul_data.data, KEY_BITS / 8); crypto_explicit_bzero(dev_data->mf_ul_data.data, KEY_BITS / 8);
if (!ret) { if(!ret) {
crypto_ctx_clear(state->crypto_ctx); crypto_ctx_clear(state->crypto_ctx);
return false; return false;
} }
/* set encrypted flag */ /* set encrypted flag */
state->encrypted = true; state->encrypted = true;
return true; return true;
} }
static void key_read_popup_set_state(ESubGhzChatState *state, KeyReadPopupState static void key_read_popup_set_state(ESubGhzChatState* state, KeyReadPopupState new_state) {
new_state) uint32_t cur_state =
{ scene_manager_get_scene_state(state->scene_manager, ESubGhzChatScene_KeyReadPopup);
uint32_t cur_state = scene_manager_get_scene_state( if(cur_state == new_state) {
state->scene_manager, ESubGhzChatScene_KeyReadPopup); return;
if (cur_state == new_state) { }
return;
}
if (new_state == KeyReadPopupState_Detecting) { if(new_state == KeyReadPopupState_Detecting) {
popup_reset(state->nfc_popup); popup_reset(state->nfc_popup);
popup_disable_timeout(state->nfc_popup); popup_disable_timeout(state->nfc_popup);
popup_set_text(state->nfc_popup, "Tap Flipper\n to sender", 97, popup_set_text(state->nfc_popup, "Tap Flipper\n to sender", 97, 24, AlignCenter, AlignTop);
24, AlignCenter, AlignTop); popup_set_icon(state->nfc_popup, 0, 8, &I_NFC_manual_60x50);
popup_set_icon(state->nfc_popup, 0, 8, &I_NFC_manual_60x50); notification_message(state->notification, &sequence_blink_start_cyan);
notification_message(state->notification, } else if(new_state == KeyReadPopupState_Reading) {
&sequence_blink_start_cyan); popup_reset(state->nfc_popup);
} else if (new_state == KeyReadPopupState_Reading) { popup_disable_timeout(state->nfc_popup);
popup_reset(state->nfc_popup); popup_set_header(
popup_disable_timeout(state->nfc_popup); state->nfc_popup,
popup_set_header(state->nfc_popup, "Reading key\nDon't " "Reading key\nDon't "
"move...", 85, 24, AlignCenter, AlignTop); "move...",
popup_set_icon(state->nfc_popup, 12, 23, &I_Loading_24); 85,
notification_message(state->notification, 24,
&sequence_blink_start_yellow); AlignCenter,
} else if (new_state == KeyReadPopupState_Fail) { AlignTop);
nfc_worker_stop(state->nfc_worker); popup_set_icon(state->nfc_popup, 12, 23, &I_Loading_24);
notification_message(state->notification, &sequence_blink_start_yellow);
} else if(new_state == KeyReadPopupState_Fail) {
nfc_worker_stop(state->nfc_worker);
popup_reset(state->nfc_popup); popup_reset(state->nfc_popup);
popup_set_header(state->nfc_popup, "Failure!", 64, 2, popup_set_header(state->nfc_popup, "Failure!", 64, 2, AlignCenter, AlignTop);
AlignCenter, AlignTop); popup_set_text(state->nfc_popup, "Failed\nto read\nkey.", 78, 16, AlignLeft, AlignTop);
popup_set_text(state->nfc_popup, "Failed\nto read\nkey.", 78, popup_set_icon(state->nfc_popup, 21, 13, &I_Cry_dolph_55x52);
16, AlignLeft, AlignTop);
popup_set_icon(state->nfc_popup, 21, 13, &I_Cry_dolph_55x52);
popup_set_timeout(state->nfc_popup, KEY_READ_POPUP_MS); popup_set_timeout(state->nfc_popup, KEY_READ_POPUP_MS);
popup_set_context(state->nfc_popup, state); popup_set_context(state->nfc_popup, state);
popup_set_callback(state->nfc_popup, popup_set_callback(state->nfc_popup, key_read_popup_timeout_cb);
key_read_popup_timeout_cb); popup_enable_timeout(state->nfc_popup);
popup_enable_timeout(state->nfc_popup);
notification_message(state->notification, notification_message(state->notification, &sequence_blink_stop);
&sequence_blink_stop); } else if(new_state == KeyReadPopupState_Success) {
} else if (new_state == KeyReadPopupState_Success) { nfc_worker_stop(state->nfc_worker);
nfc_worker_stop(state->nfc_worker);
popup_reset(state->nfc_popup); popup_reset(state->nfc_popup);
popup_set_header(state->nfc_popup, "Key\nread!", 13, 22, popup_set_header(state->nfc_popup, "Key\nread!", 13, 22, AlignLeft, AlignBottom);
AlignLeft, AlignBottom); popup_set_icon(state->nfc_popup, 32, 5, &I_DolphinNice_96x59);
popup_set_icon(state->nfc_popup, 32, 5, &I_DolphinNice_96x59);
popup_set_timeout(state->nfc_popup, KEY_READ_POPUP_MS); popup_set_timeout(state->nfc_popup, KEY_READ_POPUP_MS);
popup_set_context(state->nfc_popup, state); popup_set_context(state->nfc_popup, state);
popup_set_callback(state->nfc_popup, popup_set_callback(state->nfc_popup, key_read_popup_timeout_cb);
key_read_popup_timeout_cb); popup_enable_timeout(state->nfc_popup);
popup_enable_timeout(state->nfc_popup);
notification_message(state->notification, &sequence_success); notification_message(state->notification, &sequence_success);
notification_message(state->notification, notification_message(state->notification, &sequence_blink_stop);
&sequence_blink_stop); }
}
scene_manager_set_scene_state(state->scene_manager, scene_manager_set_scene_state(state->scene_manager, ESubGhzChatScene_KeyReadPopup, new_state);
ESubGhzChatScene_KeyReadPopup, new_state);
view_dispatcher_switch_to_view(state->view_dispatcher, view_dispatcher_switch_to_view(state->view_dispatcher, ESubGhzChatView_NfcPopup);
ESubGhzChatView_NfcPopup);
} }
/* Prepares the key share read scene. */ /* Prepares the key share read scene. */
void scene_on_enter_key_read_popup(void* context) void scene_on_enter_key_read_popup(void* context) {
{ FURI_LOG_T(APPLICATION_NAME, "scene_on_enter_key_read_popup");
FURI_LOG_T(APPLICATION_NAME, "scene_on_enter_key_read_popup");
furi_assert(context); furi_assert(context);
ESubGhzChatState* state = context; ESubGhzChatState* state = context;
key_read_popup_set_state(state, KeyReadPopupState_Detecting); key_read_popup_set_state(state, KeyReadPopupState_Detecting);
state->nfc_dev_data->parsed_data = furi_string_alloc(); state->nfc_dev_data->parsed_data = furi_string_alloc();
if (state->nfc_dev_data->parsed_data == NULL) { if(state->nfc_dev_data->parsed_data == NULL) {
/* can't do anything here, crash */ /* can't do anything here, crash */
furi_check(0); furi_check(0);
} }
nfc_worker_start(state->nfc_worker, NfcWorkerStateRead, nfc_worker_start(
state->nfc_dev_data, read_worker_cb, state); state->nfc_worker, NfcWorkerStateRead, state->nfc_dev_data, read_worker_cb, state);
} }
/* Handles scene manager events for the key read popup scene. */ /* Handles scene manager events for the key read popup scene. */
bool scene_on_event_key_read_popup(void* context, SceneManagerEvent event) bool scene_on_event_key_read_popup(void* context, SceneManagerEvent event) {
{ FURI_LOG_T(APPLICATION_NAME, "scene_on_event_key_read_popup");
FURI_LOG_T(APPLICATION_NAME, "scene_on_event_key_read_popup");
furi_assert(context); furi_assert(context);
ESubGhzChatState* state = context; ESubGhzChatState* state = context;
bool consumed = false; bool consumed = false;
switch(event.type) { switch(event.type) {
case SceneManagerEventTypeCustom: case SceneManagerEventTypeCustom:
switch(event.event) { switch(event.event) {
/* card detected */ /* card detected */
case NfcWorkerEventCardDetected: case NfcWorkerEventCardDetected:
key_read_popup_set_state(state, key_read_popup_set_state(state, KeyReadPopupState_Reading);
KeyReadPopupState_Reading); consumed = true;
consumed = true; break;
break;
/* no card detected */ /* no card detected */
case NfcWorkerEventNoCardDetected: case NfcWorkerEventNoCardDetected:
key_read_popup_set_state(state, key_read_popup_set_state(state, KeyReadPopupState_Detecting);
KeyReadPopupState_Detecting); consumed = true;
consumed = true; break;
break;
/* key probably read */ /* key probably read */
case NfcWorkerEventReadMfUltralight: case NfcWorkerEventReadMfUltralight:
if (key_read_popup_handle_key_read(state)) { if(key_read_popup_handle_key_read(state)) {
key_read_popup_set_state(state, key_read_popup_set_state(state, KeyReadPopupState_Success);
KeyReadPopupState_Success); } else {
} else { key_read_popup_set_state(state, KeyReadPopupState_Fail);
key_read_popup_set_state(state, }
KeyReadPopupState_Fail); consumed = true;
} break;
consumed = true;
break;
/* close the popup and go back */ /* close the popup and go back */
case ESubGhzChatEvent_KeyReadPopupFailed: case ESubGhzChatEvent_KeyReadPopupFailed:
if (!scene_manager_previous_scene( if(!scene_manager_previous_scene(state->scene_manager)) {
state->scene_manager)) { view_dispatcher_stop(state->view_dispatcher);
view_dispatcher_stop(state->view_dispatcher); }
} consumed = true;
consumed = true; break;
break;
/* success, go to chat input */ /* success, go to chat input */
case ESubGhzChatEvent_KeyReadPopupSucceeded: case ESubGhzChatEvent_KeyReadPopupSucceeded:
scene_manager_next_scene(state->scene_manager, scene_manager_next_scene(state->scene_manager, ESubGhzChatScene_ChatInput);
ESubGhzChatScene_ChatInput); consumed = true;
consumed = true; break;
break;
/* something else happend, treat as failure */ /* something else happend, treat as failure */
default: default:
key_read_popup_set_state(state, key_read_popup_set_state(state, KeyReadPopupState_Fail);
KeyReadPopupState_Fail); consumed = true;
consumed = true; break;
break; }
}
break; break;
default: default:
consumed = false; consumed = false;
break; break;
} }
return consumed; return consumed;
} }
/* Cleans up the key read popup scene. */ /* Cleans up the key read popup scene. */
void scene_on_exit_key_read_popup(void* context) void scene_on_exit_key_read_popup(void* context) {
{ FURI_LOG_T(APPLICATION_NAME, "scene_on_exit_key_read_popup");
FURI_LOG_T(APPLICATION_NAME, "scene_on_exit_key_read_popup");
furi_assert(context); furi_assert(context);
ESubGhzChatState* state = context; ESubGhzChatState* state = context;
popup_reset(state->nfc_popup); popup_reset(state->nfc_popup);
scene_manager_set_scene_state(state->scene_manager, scene_manager_set_scene_state(
ESubGhzChatScene_KeyReadPopup, KeyReadPopupState_Idle); state->scene_manager, ESubGhzChatScene_KeyReadPopup, KeyReadPopupState_Idle);
notification_message(state->notification, &sequence_blink_stop); notification_message(state->notification, &sequence_blink_stop);
nfc_worker_stop(state->nfc_worker); nfc_worker_stop(state->nfc_worker);
crypto_explicit_bzero(state->nfc_dev_data->mf_ul_data.data, KEY_BITS / 8); crypto_explicit_bzero(state->nfc_dev_data->mf_ul_data.data, KEY_BITS / 8);
if (state->nfc_dev_data->parsed_data != NULL) { if(state->nfc_dev_data->parsed_data != NULL) {
furi_string_free(state->nfc_dev_data->parsed_data); furi_string_free(state->nfc_dev_data->parsed_data);
} }
memset(state->nfc_dev_data, 0, sizeof(NfcDeviceData)); memset(state->nfc_dev_data, 0, sizeof(NfcDeviceData));
} }

View File

@@ -1,88 +1,80 @@
#include "../esubghz_chat_i.h" #include "../esubghz_chat_i.h"
static void prepare_nfc_dev_data(ESubGhzChatState *state) static void prepare_nfc_dev_data(ESubGhzChatState* state) {
{ NfcDeviceData* dev_data = state->nfc_dev_data;
NfcDeviceData *dev_data = state->nfc_dev_data;
dev_data->protocol = NfcDeviceProtocolMifareUl; dev_data->protocol = NfcDeviceProtocolMifareUl;
furi_hal_random_fill_buf(dev_data->nfc_data.uid, 7); furi_hal_random_fill_buf(dev_data->nfc_data.uid, 7);
dev_data->nfc_data.uid_len = 7; dev_data->nfc_data.uid_len = 7;
dev_data->nfc_data.atqa[0] = 0x44; dev_data->nfc_data.atqa[0] = 0x44;
dev_data->nfc_data.atqa[1] = 0x00; dev_data->nfc_data.atqa[1] = 0x00;
dev_data->nfc_data.sak = 0x00; dev_data->nfc_data.sak = 0x00;
dev_data->mf_ul_data.type = MfUltralightTypeNTAG215; dev_data->mf_ul_data.type = MfUltralightTypeNTAG215;
dev_data->mf_ul_data.version.header = 0x00; dev_data->mf_ul_data.version.header = 0x00;
dev_data->mf_ul_data.version.vendor_id = 0x04; dev_data->mf_ul_data.version.vendor_id = 0x04;
dev_data->mf_ul_data.version.prod_type = 0x04; dev_data->mf_ul_data.version.prod_type = 0x04;
dev_data->mf_ul_data.version.prod_subtype = 0x02; dev_data->mf_ul_data.version.prod_subtype = 0x02;
dev_data->mf_ul_data.version.prod_ver_major = 0x01; dev_data->mf_ul_data.version.prod_ver_major = 0x01;
dev_data->mf_ul_data.version.prod_ver_minor = 0x00; dev_data->mf_ul_data.version.prod_ver_minor = 0x00;
dev_data->mf_ul_data.version.storage_size = 0x11; dev_data->mf_ul_data.version.storage_size = 0x11;
dev_data->mf_ul_data.version.protocol_type = 0x03; dev_data->mf_ul_data.version.protocol_type = 0x03;
/* Add 16 to the size for config pages */ /* Add 16 to the size for config pages */
dev_data->mf_ul_data.data_size = (KEY_BITS / 8) + 16; dev_data->mf_ul_data.data_size = (KEY_BITS / 8) + 16;
crypto_ctx_get_key(state->crypto_ctx, dev_data->mf_ul_data.data); crypto_ctx_get_key(state->crypto_ctx, dev_data->mf_ul_data.data);
} }
/* Prepares the key share popup scene. */ /* Prepares the key share popup scene. */
void scene_on_enter_key_share_popup(void* context) void scene_on_enter_key_share_popup(void* context) {
{ FURI_LOG_T(APPLICATION_NAME, "scene_on_enter_key_share_popup");
FURI_LOG_T(APPLICATION_NAME, "scene_on_enter_key_share_popup");
furi_assert(context); furi_assert(context);
ESubGhzChatState* state = context; ESubGhzChatState* state = context;
popup_reset(state->nfc_popup); popup_reset(state->nfc_popup);
popup_disable_timeout(state->nfc_popup); popup_disable_timeout(state->nfc_popup);
popup_set_header(state->nfc_popup, "Sharing...", 67, 13, AlignLeft, popup_set_header(state->nfc_popup, "Sharing...", 67, 13, AlignLeft, AlignTop);
AlignTop); popup_set_icon(state->nfc_popup, 0, 3, &I_NFC_dolphin_emulation_47x61);
popup_set_icon(state->nfc_popup, 0, 3, &I_NFC_dolphin_emulation_47x61); popup_set_text(state->nfc_popup, "Sharing\nKey via\nNFC", 90, 28, AlignCenter, AlignTop);
popup_set_text(state->nfc_popup, "Sharing\nKey via\nNFC", 90, 28,
AlignCenter, AlignTop);
prepare_nfc_dev_data(state); prepare_nfc_dev_data(state);
nfc_worker_start(state->nfc_worker, NfcWorkerStateMfUltralightEmulate, nfc_worker_start(
state->nfc_dev_data, NULL, NULL); state->nfc_worker, NfcWorkerStateMfUltralightEmulate, state->nfc_dev_data, NULL, NULL);
notification_message(state->notification, notification_message(state->notification, &sequence_blink_start_magenta);
&sequence_blink_start_magenta);
view_dispatcher_switch_to_view(state->view_dispatcher, view_dispatcher_switch_to_view(state->view_dispatcher, ESubGhzChatView_NfcPopup);
ESubGhzChatView_NfcPopup);
} }
/* Handles scene manager events for the key share popup scene. */ /* Handles scene manager events for the key share popup scene. */
bool scene_on_event_key_share_popup(void* context, SceneManagerEvent event) bool scene_on_event_key_share_popup(void* context, SceneManagerEvent event) {
{ FURI_LOG_T(APPLICATION_NAME, "scene_on_event_key_share_popup");
FURI_LOG_T(APPLICATION_NAME, "scene_on_event_key_share_popup");
furi_assert(context); furi_assert(context);
ESubGhzChatState* state = context; ESubGhzChatState* state = context;
UNUSED(state); UNUSED(state);
UNUSED(event); UNUSED(event);
return false; return false;
} }
/* Cleans up the key share popup scene. */ /* Cleans up the key share popup scene. */
void scene_on_exit_key_share_popup(void* context) void scene_on_exit_key_share_popup(void* context) {
{ FURI_LOG_T(APPLICATION_NAME, "scene_on_exit_key_share_popup");
FURI_LOG_T(APPLICATION_NAME, "scene_on_exit_key_share_popup");
furi_assert(context); furi_assert(context);
ESubGhzChatState* state = context; ESubGhzChatState* state = context;
popup_reset(state->nfc_popup); popup_reset(state->nfc_popup);
notification_message(state->notification, &sequence_blink_stop); notification_message(state->notification, &sequence_blink_stop);
nfc_worker_stop(state->nfc_worker); nfc_worker_stop(state->nfc_worker);
crypto_explicit_bzero(state->nfc_dev_data->mf_ul_data.data, KEY_BITS / 8); crypto_explicit_bzero(state->nfc_dev_data->mf_ul_data.data, KEY_BITS / 8);
memset(state->nfc_dev_data, 0, sizeof(NfcDeviceData)); memset(state->nfc_dev_data, 0, sizeof(NfcDeviceData));
} }

View File

@@ -1,127 +1,111 @@
#include "../esubghz_chat_i.h" #include "../esubghz_chat_i.h"
/* Sends PassEntered event to scene manager and enters the chat. */ /* Sends PassEntered event to scene manager and enters the chat. */
static void pass_input_cb(void *context) static void pass_input_cb(void* context) {
{ furi_assert(context);
furi_assert(context); ESubGhzChatState* state = context;
ESubGhzChatState* state = context;
crypto_explicit_bzero(state->text_input_store, crypto_explicit_bzero(state->text_input_store, sizeof(state->text_input_store));
sizeof(state->text_input_store));
enter_chat(state); enter_chat(state);
view_dispatcher_send_custom_event(state->view_dispatcher, view_dispatcher_send_custom_event(state->view_dispatcher, ESubGhzChatEvent_PassEntered);
ESubGhzChatEvent_PassEntered);
} }
/* If a password was entered this derives a key from the password using a /* If a password was entered this derives a key from the password using a
* single pass of SHA256 and initiates the AES-GCM context for encryption. If * single pass of SHA256 and initiates the AES-GCM context for encryption. If
* the initiation fails, the password is rejected. */ * the initiation fails, the password is rejected. */
static bool pass_input_validator(const char *text, FuriString *error, static bool pass_input_validator(const char* text, FuriString* error, void* context) {
void *context) furi_assert(text);
{ furi_assert(error);
furi_assert(text);
furi_assert(error);
furi_assert(context); furi_assert(context);
ESubGhzChatState* state = context; ESubGhzChatState* state = context;
if (strlen(text) == 0) { if(strlen(text) == 0) {
furi_string_printf(error, "Enter a\npassword!"); furi_string_printf(error, "Enter a\npassword!");
return false; return false;
} }
unsigned char key[KEY_BITS / 8]; unsigned char key[KEY_BITS / 8];
/* derive a key from the password */ /* derive a key from the password */
sha256((unsigned char *) text, strlen(text), key); sha256((unsigned char*)text, strlen(text), key);
/* initiate the crypto context */ /* initiate the crypto context */
bool ret = crypto_ctx_set_key(state->crypto_ctx, key, bool ret = crypto_ctx_set_key(state->crypto_ctx, key, state->name_prefix, furi_get_tick());
state->name_prefix, furi_get_tick());
/* cleanup */ /* cleanup */
crypto_explicit_bzero(key, sizeof(key)); crypto_explicit_bzero(key, sizeof(key));
if (!ret) { if(!ret) {
crypto_ctx_clear(state->crypto_ctx); crypto_ctx_clear(state->crypto_ctx);
furi_string_printf(error, "Failed to\nset key!"); furi_string_printf(error, "Failed to\nset key!");
return false; return false;
} }
state->encrypted = true; state->encrypted = true;
return true; return true;
} }
/* Prepares the password input scene. */ /* Prepares the password input scene. */
void scene_on_enter_pass_input(void* context) void scene_on_enter_pass_input(void* context) {
{ FURI_LOG_T(APPLICATION_NAME, "scene_on_enter_pass_input");
FURI_LOG_T(APPLICATION_NAME, "scene_on_enter_pass_input");
furi_assert(context); furi_assert(context);
ESubGhzChatState* state = context; ESubGhzChatState* state = context;
state->text_input_store[0] = 0; state->text_input_store[0] = 0;
text_input_reset(state->text_input); text_input_reset(state->text_input);
text_input_set_result_callback( text_input_set_result_callback(
state->text_input, state->text_input,
pass_input_cb, pass_input_cb,
state, state,
state->text_input_store, state->text_input_store,
sizeof(state->text_input_store), sizeof(state->text_input_store),
true); true);
text_input_set_validator( text_input_set_validator(state->text_input, pass_input_validator, state);
state->text_input, text_input_set_header_text(state->text_input, "Password");
pass_input_validator,
state);
text_input_set_header_text(
state->text_input,
"Password");
view_dispatcher_switch_to_view(state->view_dispatcher, ESubGhzChatView_Input); view_dispatcher_switch_to_view(state->view_dispatcher, ESubGhzChatView_Input);
} }
/* Handles scene manager events for the password input scene. */ /* Handles scene manager events for the password input scene. */
bool scene_on_event_pass_input(void* context, SceneManagerEvent event) bool scene_on_event_pass_input(void* context, SceneManagerEvent event) {
{ FURI_LOG_T(APPLICATION_NAME, "scene_on_event_pass_input");
FURI_LOG_T(APPLICATION_NAME, "scene_on_event_pass_input");
furi_assert(context); furi_assert(context);
ESubGhzChatState* state = context; ESubGhzChatState* state = context;
bool consumed = false; bool consumed = false;
switch(event.type) { switch(event.type) {
case SceneManagerEventTypeCustom: case SceneManagerEventTypeCustom:
switch(event.event) { switch(event.event) {
/* switch to message input scene */ /* switch to message input scene */
case ESubGhzChatEvent_PassEntered: case ESubGhzChatEvent_PassEntered:
scene_manager_next_scene(state->scene_manager, scene_manager_next_scene(state->scene_manager, ESubGhzChatScene_ChatInput);
ESubGhzChatScene_ChatInput); consumed = true;
consumed = true; break;
break; }
} break;
break;
default: default:
consumed = false; consumed = false;
break; break;
} }
return consumed; return consumed;
} }
/* Cleans up the password input scene. */ /* Cleans up the password input scene. */
void scene_on_exit_pass_input(void* context) void scene_on_exit_pass_input(void* context) {
{ FURI_LOG_T(APPLICATION_NAME, "scene_on_exit_pass_input");
FURI_LOG_T(APPLICATION_NAME, "scene_on_exit_pass_input");
furi_assert(context); furi_assert(context);
ESubGhzChatState* state = context; ESubGhzChatState* state = context;
text_input_reset(state->text_input); text_input_reset(state->text_input);
crypto_explicit_bzero(state->text_input_store, crypto_explicit_bzero(state->text_input_store, sizeof(state->text_input_store));
sizeof(state->text_input_store));
} }

View File

@@ -6,7 +6,7 @@
#define ADD_SCENE(prefix, name, id) ESubGhzChatScene_##id, #define ADD_SCENE(prefix, name, id) ESubGhzChatScene_##id,
typedef enum { typedef enum {
#include "esubghz_chat_scene_config.h" #include "esubghz_chat_scene_config.h"
ESubGhzChatScene_MAX ESubGhzChatScene_MAX
} ESubGhzChatScene; } ESubGhzChatScene;
#undef ADD_SCENE #undef ADD_SCENE
@@ -19,7 +19,7 @@ extern const SceneManagerHandlers esubghz_chat_scene_event_handlers;
// Generate scene on_event handlers declaration // Generate scene on_event handlers declaration
#define ADD_SCENE(prefix, name, id) \ #define ADD_SCENE(prefix, name, id) \
bool scene_on_event_##name(void* context, SceneManagerEvent event); bool scene_on_event_##name(void* context, SceneManagerEvent event);
#include "esubghz_chat_scene_config.h" #include "esubghz_chat_scene_config.h"
#undef ADD_SCENE #undef ADD_SCENE

View File

@@ -9,23 +9,20 @@
#include "wire_tester_icons.h" #include "wire_tester_icons.h"
//#define TAG "wire_tester" //#define TAG "wire_tester"
static const uint32_t EVENT_PERIOD_MS = 10; // check for input changes often static const uint32_t EVENT_PERIOD_MS = 10; // check for input changes often
static const float BEEP_FREQ = 2400.0f; // louder than other frequencies static const float BEEP_FREQ = 2400.0f; // louder than other frequencies
static const float BEEP_VOL = 0.8f; static const float BEEP_VOL = 0.8f;
static const GpioPin* const INPUT_PIN = &gpio_ext_pb2; // pin 6 static const GpioPin* const INPUT_PIN = &gpio_ext_pb2; // pin 6
static void start_feedback(NotificationApp* notifications) { static void start_feedback(NotificationApp* notifications) {
// set LED to green // set LED to green
notification_message_block(notifications, &sequence_set_only_green_255); notification_message_block(notifications, &sequence_set_only_green_255);
// start beep // start beep
if (furi_hal_speaker_acquire(1000)) { if(furi_hal_speaker_acquire(1000)) {
furi_hal_speaker_start(BEEP_FREQ, BEEP_VOL); furi_hal_speaker_start(BEEP_FREQ, BEEP_VOL);
} }
} }
@@ -34,7 +31,7 @@ static void stop_feedback(NotificationApp* notifications) {
notification_message_block(notifications, &sequence_reset_rgb); notification_message_block(notifications, &sequence_reset_rgb);
// stop beep // stop beep
if (furi_hal_speaker_is_mine()) { if(furi_hal_speaker_is_mine()) {
furi_hal_speaker_stop(); furi_hal_speaker_stop();
furi_hal_speaker_release(); furi_hal_speaker_release();
} }
@@ -75,21 +72,21 @@ int32_t app_main(void* p) {
bool alarming = false; bool alarming = false;
bool running = true; bool running = true;
while (running) { while(running) {
// start and stop feedback on the transition // start and stop feedback on the transition
bool continuous = !furi_hal_gpio_read(INPUT_PIN); bool continuous = !furi_hal_gpio_read(INPUT_PIN);
if (continuous && !alarming) { if(continuous && !alarming) {
start_feedback(notifications); start_feedback(notifications);
} else if (!continuous && alarming) { } else if(!continuous && alarming) {
stop_feedback(notifications); stop_feedback(notifications);
} }
alarming = continuous; alarming = continuous;
// exit on back key // exit on back key
InputEvent event; InputEvent event;
if (furi_message_queue_get(event_queue, &event, EVENT_PERIOD_MS) == FuriStatusOk) { if(furi_message_queue_get(event_queue, &event, EVENT_PERIOD_MS) == FuriStatusOk) {
if ((event.type == InputTypePress || event.type == InputTypeRepeat) if((event.type == InputTypePress || event.type == InputTypeRepeat) &&
&& event.key == InputKeyBack) { event.key == InputKeyBack) {
running = false; running = false;
} }
} }