Last active
February 2, 2022 18:46
-
-
Save CC-Dh/deef9cd1fa1d3272c72bc46964f318d4 to your computer and use it in GitHub Desktop.
LittleFS AES
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* \brief Generic file encryption program using generic wrappers for configured | |
* security. | |
* | |
* Copyright The Mbed TLS Contributors | |
* SPDX-License-Identifier: Apache-2.0 | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); you may | |
* not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
/* | |
* This file (originally crypt_and_hash.c) is modified by CC Dharmani (Jan 2022) to suit | |
R-Pi Pico, Arduino-mbed, renamed here as fileAES.cpp. | |
* The main(argc,arg[v]) function declaration is replaced with fileAES(arguments) function. | |
* Tested on Raspberry Pi Pico board (Arduino-mbed, on PlatformIO). | |
*/ | |
#include "fileAES.h" | |
#if defined(MBEDTLS_CIPHER_C) && defined(MBEDTLS_MD_C) && defined(MBEDTLS_FS_IO) | |
#include "mbedtls/cipher.h" | |
#include "mbedtls/md.h" | |
#include "mbedtls/aes.h" | |
#include "mbedtls/platform_util.h" | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <sys/types.h> | |
#include <unistd.h> | |
int fileAES (int modeIn, char* inFilename, char* outFilename, char* cipher, char* mbedtls_md, char* keyIn) | |
{ | |
int ret = 1, i; | |
unsigned n; | |
int exit_code = MBEDTLS_EXIT_FAILURE; | |
int mode; | |
size_t keylen, ilen, olen; | |
FILE *fkey, *fin = NULL, *fout = NULL; | |
char *p; | |
unsigned char IV[16]; | |
unsigned char key[512]; | |
unsigned char digest[MBEDTLS_MD_MAX_SIZE]; | |
unsigned char buffer[512]; | |
unsigned char output[512]; | |
unsigned char diff; | |
const mbedtls_cipher_info_t *cipher_info; | |
const mbedtls_md_info_t *md_info; | |
mbedtls_cipher_context_t cipher_ctx; | |
mbedtls_md_context_t md_ctx; | |
#if defined(_WIN32_WCE) | |
long filesize, offset; | |
#elif defined(_WIN32) | |
LARGE_INTEGER li_size; | |
__int64 filesize, offset; | |
#else | |
off_t filesize, offset; | |
#endif | |
mbedtls_cipher_init( &cipher_ctx ); | |
mbedtls_md_init( &md_ctx ); | |
mode = modeIn; | |
if( mode != MODE_ENCRYPT && mode != MODE_DECRYPT ) | |
{ | |
mbedtls_fprintf( stderr, "invalid operation mode\n" ); | |
goto exit; | |
} | |
if( strcmp( inFilename, outFilename) == 0 ) | |
{ | |
mbedtls_fprintf( stderr, "input and output filenames must differ\n" ); | |
goto exit; | |
} | |
if( ( fin = fopen( inFilename, "rb" ) ) == NULL ) | |
{ | |
mbedtls_fprintf( stderr, "fopen(%s,rb) failed\n", inFilename ); | |
goto exit; | |
} | |
if( ( fout = fopen( outFilename, "wb+" ) ) == NULL ) | |
{ | |
mbedtls_fprintf( stderr, "fopen(%s,wb+) failed\n", outFilename ); | |
goto exit; | |
} | |
/* | |
* Read the Cipher and MD from the command line | |
*/ | |
cipher_info = mbedtls_cipher_info_from_string( cipher ); | |
if( cipher_info == NULL ) | |
{ | |
mbedtls_fprintf( stderr, "Cipher '%s' not found\n", cipher ); | |
goto exit; | |
} | |
if( ( ret = mbedtls_cipher_setup( &cipher_ctx, cipher_info) ) != 0 ) | |
{ | |
mbedtls_fprintf( stderr, "mbedtls_cipher_setup failed\n" ); | |
goto exit; | |
} | |
md_info = mbedtls_md_info_from_string( mbedtls_md ); | |
if( md_info == NULL ) | |
{ | |
mbedtls_fprintf( stderr, "Message Digest '%s' not found\n", mbedtls_md ); | |
goto exit; | |
} | |
if( mbedtls_md_setup( &md_ctx, md_info, 1 ) != 0 ) | |
{ | |
mbedtls_fprintf( stderr, "mbedtls_md_setup failed\n" ); | |
goto exit; | |
} | |
/* | |
* Read the secret key from file or command line | |
*/ | |
if( ( fkey = fopen( keyIn, "rb" ) ) != NULL ) | |
{ | |
keylen = fread( key, 1, sizeof( key ), fkey ); | |
fclose( fkey ); | |
} | |
else | |
{ | |
if( memcmp( keyIn, "hex:", 4 ) == 0 ) | |
{ | |
p = &keyIn[4]; | |
keylen = 0; | |
while( sscanf( p, "%02X", (unsigned int*) &n ) > 0 && | |
keylen < (int) sizeof( key ) ) | |
{ | |
key[keylen++] = (unsigned char) n; | |
p += 2; | |
} | |
} | |
else | |
{ | |
keylen = strlen( keyIn ); | |
if( keylen > (int) sizeof( key ) ) | |
keylen = (int) sizeof( key ); | |
memcpy( key, keyIn, keylen ); | |
} | |
} | |
#if defined(_WIN32_WCE) | |
filesize = fseek( fin, 0L, SEEK_END ); | |
#else | |
#if defined(_WIN32) | |
/* | |
* Support large files (> 2Gb) on Win32 | |
*/ | |
li_size.QuadPart = 0; | |
li_size.LowPart = | |
SetFilePointer( (HANDLE) _get_osfhandle( _fileno( fin ) ), | |
li_size.LowPart, &li_size.HighPart, FILE_END ); | |
if( li_size.LowPart == 0xFFFFFFFF && GetLastError() != NO_ERROR ) | |
{ | |
mbedtls_fprintf( stderr, "SetFilePointer(0,FILE_END) failed\n" ); | |
goto exit; | |
} | |
filesize = li_size.QuadPart; | |
#else | |
if(fseek(fin, 0L, SEEK_END) < 0) | |
{ | |
perror( "fseek" ); | |
goto exit; | |
} | |
filesize = ftell(fin); | |
//mbedtls_fprintf( stdout, "\nInput File size: %ld bytes\n", (long)filesize ); | |
/* | |
if( ( filesize = lseek( fileno( fin ), 0, SEEK_END ) ) < 0 ) | |
{ | |
perror( "lseek" ); | |
goto exit; | |
} | |
*/ | |
#endif | |
#endif | |
if( fseek( fin, 0, SEEK_SET ) < 0 ) | |
{ | |
mbedtls_fprintf( stderr, "fseek(0,SEEK_SET) failed\n" ); | |
goto exit; | |
} | |
if( mode == MODE_ENCRYPT ) | |
{ | |
/* | |
* Generate the initialization vector as: | |
* IV = MD( filesize || filename )[0..15] | |
*/ | |
for( i = 0; i < 8; i++ ) | |
buffer[i] = (unsigned char)( filesize >> ( i << 3 ) ); | |
p = inFilename; | |
if( mbedtls_md_starts( &md_ctx ) != 0 ) | |
{ | |
mbedtls_fprintf( stderr, "mbedtls_md_starts() returned error\n" ); | |
goto exit; | |
} | |
if( mbedtls_md_update( &md_ctx, buffer, 8 ) != 0 ) | |
{ | |
mbedtls_fprintf( stderr, "mbedtls_md_update() returned error\n" ); | |
goto exit; | |
} | |
if( mbedtls_md_update( &md_ctx, ( unsigned char * ) p, strlen( p ) ) | |
!= 0 ) | |
{ | |
mbedtls_fprintf( stderr, "mbedtls_md_update() returned error\n" ); | |
goto exit; | |
} | |
if( mbedtls_md_finish( &md_ctx, digest ) != 0 ) | |
{ | |
mbedtls_fprintf( stderr, "mbedtls_md_finish() returned error\n" ); | |
goto exit; | |
} | |
memcpy( IV, digest, 16 ); | |
/* | |
mbedtls_fprintf( stdout, "\nEncode IV: " ); | |
for(int i=0; i<16; i++) mbedtls_fprintf( stdout, "0x%02x ", IV[i]); | |
mbedtls_fprintf( stdout, "\n"); | |
*/ | |
/* | |
* Append the IV at the beginning of the output. | |
*/ | |
if( fwrite( IV, 1, 16, fout ) != 16 ) | |
{ | |
mbedtls_fprintf( stderr, "fwrite(%d bytes) failed\n", 16 ); | |
goto exit; | |
} | |
/* | |
* Hash the IV and the secret key together 8192 times | |
* using the result to setup the AES context and HMAC. | |
*/ | |
memset( digest, 0, 32 ); | |
memcpy( digest, IV, 16 ); | |
for( i = 0; i < 8192; i++ ) | |
{ | |
if( mbedtls_md_starts( &md_ctx ) != 0 ) | |
{ | |
mbedtls_fprintf( stderr, | |
"mbedtls_md_starts() returned error\n" ); | |
goto exit; | |
} | |
if( mbedtls_md_update( &md_ctx, digest, 32 ) != 0 ) | |
{ | |
mbedtls_fprintf( stderr, | |
"mbedtls_md_update() returned error\n" ); | |
goto exit; | |
} | |
if( mbedtls_md_update( &md_ctx, key, keylen ) != 0 ) | |
{ | |
mbedtls_fprintf( stderr, | |
"mbedtls_md_update() returned error\n" ); | |
goto exit; | |
} | |
if( mbedtls_md_finish( &md_ctx, digest ) != 0 ) | |
{ | |
mbedtls_fprintf( stderr, | |
"mbedtls_md_finish() returned error\n" ); | |
goto exit; | |
} | |
} | |
if( mbedtls_cipher_setkey( &cipher_ctx, | |
digest, | |
//(int) mbedtls_cipher_info_get_key_bitlen( cipher_info ), | |
mbedtls_cipher_get_key_bitlen ( &cipher_ctx), | |
MBEDTLS_ENCRYPT ) != 0 ) | |
{ | |
mbedtls_fprintf( stderr, "mbedtls_cipher_setkey() returned error\n"); | |
goto exit; | |
} | |
if( mbedtls_cipher_set_iv( &cipher_ctx, IV, 16 ) != 0 ) | |
{ | |
mbedtls_fprintf( stderr, "mbedtls_cipher_set_iv() returned error\n"); | |
goto exit; | |
} | |
if( mbedtls_cipher_reset( &cipher_ctx ) != 0 ) | |
{ | |
mbedtls_fprintf( stderr, "mbedtls_cipher_reset() returned error\n"); | |
goto exit; | |
} | |
if( mbedtls_md_hmac_starts( &md_ctx, digest, 32 ) != 0 ) | |
{ | |
mbedtls_fprintf( stderr, "mbedtls_md_hmac_starts() returned error\n" ); | |
goto exit; | |
} | |
/* | |
* Encrypt and write the ciphertext. | |
*/ | |
for( offset = 0; offset < filesize; offset += mbedtls_cipher_get_block_size( &cipher_ctx ) ) | |
{ | |
ilen = ( (unsigned int) filesize - offset > mbedtls_cipher_get_block_size( &cipher_ctx ) ) ? | |
mbedtls_cipher_get_block_size( &cipher_ctx ) : (unsigned int) ( filesize - offset ); | |
if( fread( buffer, 1, ilen, fin ) != ilen ) | |
{ | |
mbedtls_fprintf( stderr, "fread(%ld bytes) failed\n", (long) ilen ); | |
goto exit; | |
} | |
if( mbedtls_cipher_update( &cipher_ctx, buffer, ilen, output, &olen ) != 0 ) | |
{ | |
mbedtls_fprintf( stderr, "mbedtls_cipher_update() returned error\n"); | |
goto exit; | |
} | |
if( mbedtls_md_hmac_update( &md_ctx, output, olen ) != 0 ) | |
{ | |
mbedtls_fprintf( stderr, "mbedtls_md_hmac_update() returned error\n" ); | |
goto exit; | |
} | |
if( fwrite( output, 1, olen, fout ) != olen ) | |
{ | |
mbedtls_fprintf( stderr, "fwrite(%ld bytes) failed\n", (long) olen ); | |
goto exit; | |
} | |
} | |
if( mbedtls_cipher_finish( &cipher_ctx, output, &olen ) != 0 ) | |
{ | |
mbedtls_fprintf( stderr, "mbedtls_cipher_finish() returned error\n" ); | |
goto exit; | |
} | |
if( mbedtls_md_hmac_update( &md_ctx, output, olen ) != 0 ) | |
{ | |
mbedtls_fprintf( stderr, "mbedtls_md_hmac_update() returned error\n" ); | |
goto exit; | |
} | |
if( fwrite( output, 1, olen, fout ) != olen ) | |
{ | |
mbedtls_fprintf( stderr, "fwrite(%ld bytes) failed\n", (long) olen ); | |
goto exit; | |
} | |
/* | |
* Finally write the HMAC. | |
*/ | |
if( mbedtls_md_hmac_finish( &md_ctx, digest ) != 0 ) | |
{ | |
mbedtls_fprintf( stderr, "mbedtls_md_hmac_finish() returned error\n" ); | |
goto exit; | |
} | |
if( fwrite( digest, 1, mbedtls_md_get_size( md_info ), fout ) != mbedtls_md_get_size( md_info ) ) | |
{ | |
mbedtls_fprintf( stderr, "fwrite(%d bytes) failed\n", mbedtls_md_get_size( md_info ) ); | |
goto exit; | |
} | |
} | |
if( mode == MODE_DECRYPT ) | |
{ | |
/* | |
* The encrypted file must be structured as follows: | |
* | |
* 00 .. 15 Initialization Vector | |
* 16 .. 31 Encrypted Block #1 | |
* .. | |
* N*16 .. (N+1)*16 - 1 Encrypted Block #N | |
* (N+1)*16 .. (N+1)*16 + n Hash(ciphertext) | |
*/ | |
/* | |
if( fread( buffer, 1, 16, fin ) != 16 ) | |
{ | |
mbedtls_fprintf( stderr, "fread(%d bytes) failed\n", 16 ); | |
goto exit; | |
} | |
mbedtls_fprintf( stdout, "\nRead IV: " ); | |
for(int i=0; i<16; i++) mbedtls_fprintf( stdout, "0x%02x ", buffer[i]); | |
mbedtls_fprintf( stdout, "\n"); | |
fseek( fin, 0, SEEK_SET ); | |
*/ | |
if( filesize < 16 + mbedtls_md_get_size( md_info ) ) | |
{ | |
mbedtls_fprintf( stderr, "File too short to be encrypted.\n" ); | |
goto exit; | |
} | |
if( mbedtls_cipher_get_block_size( &cipher_ctx ) == 0 ) | |
{ | |
mbedtls_fprintf( stderr, "Invalid cipher block size: 0. \n" ); | |
goto exit; | |
} | |
/* | |
* Check the file size. | |
*/ | |
//if( mbedtls_cipher_info_get_mode( cipher_info ) != MBEDTLS_MODE_GCM && | |
if( mbedtls_cipher_get_cipher_mode( &cipher_ctx ) != MBEDTLS_MODE_GCM && | |
( ( filesize - mbedtls_md_get_size( md_info ) ) % | |
mbedtls_cipher_get_block_size( &cipher_ctx ) ) != 0 ) | |
{ | |
mbedtls_fprintf( stderr, "File content not a multiple of the block size (%u).\n", | |
mbedtls_cipher_get_block_size( &cipher_ctx )); | |
goto exit; | |
} | |
/* | |
* Subtract the IV + HMAC length. | |
*/ | |
filesize -= ( 16 + mbedtls_md_get_size( md_info ) ); | |
/* | |
* Read the IV and original filesize modulo 16. | |
*/ | |
if( fread( buffer, 1, 16, fin ) != 16 ) | |
{ | |
mbedtls_fprintf( stderr, "fread(%d bytes) failed\n", 16 ); | |
goto exit; | |
} | |
memcpy( IV, buffer, 16 ); | |
/* | |
mbedtls_fprintf( stdout, "Decode IV: " ); //------------------------------------ | |
for(int i=0; i<16; i++) mbedtls_fprintf( stdout, "0x%02x ", IV[i]); | |
mbedtls_fprintf( stdout, "\n"); | |
*/ | |
/* | |
* Hash the IV and the secret key together 8192 times | |
* using the result to setup the AES context and HMAC. | |
*/ | |
memset( digest, 0, 32 ); | |
memcpy( digest, IV, 16 ); | |
for( i = 0; i < 8192; i++ ) | |
{ | |
if( mbedtls_md_starts( &md_ctx ) != 0 ) | |
{ | |
mbedtls_fprintf( stderr, "mbedtls_md_starts() returned error\n" ); | |
goto exit; | |
} | |
if( mbedtls_md_update( &md_ctx, digest, 32 ) != 0 ) | |
{ | |
mbedtls_fprintf( stderr, "mbedtls_md_update() returned error\n" ); | |
goto exit; | |
} | |
if( mbedtls_md_update( &md_ctx, key, keylen ) != 0 ) | |
{ | |
mbedtls_fprintf( stderr, "mbedtls_md_update() returned error\n" ); | |
goto exit; | |
} | |
if( mbedtls_md_finish( &md_ctx, digest ) != 0 ) | |
{ | |
mbedtls_fprintf( stderr, "mbedtls_md_finish() returned error\n" ); | |
goto exit; | |
} | |
} | |
if( mbedtls_cipher_setkey( &cipher_ctx, | |
digest, | |
//(int) mbedtls_cipher_info_get_key_bitlen( cipher_info ), | |
mbedtls_cipher_get_key_bitlen( &cipher_ctx ), | |
MBEDTLS_DECRYPT ) != 0 ) | |
{ | |
mbedtls_fprintf( stderr, "mbedtls_cipher_setkey() returned error\n" ); | |
goto exit; | |
} | |
if( mbedtls_cipher_set_iv( &cipher_ctx, IV, 16 ) != 0 ) | |
{ | |
mbedtls_fprintf( stderr, "mbedtls_cipher_set_iv() returned error\n" ); | |
goto exit; | |
} | |
if( mbedtls_cipher_reset( &cipher_ctx ) != 0 ) | |
{ | |
mbedtls_fprintf( stderr, "mbedtls_cipher_reset() returned error\n" ); | |
goto exit; | |
} | |
if( mbedtls_md_hmac_starts( &md_ctx, digest, 32 ) != 0 ) | |
{ | |
mbedtls_fprintf( stderr, "mbedtls_md_hmac_starts() returned error\n" ); | |
goto exit; | |
} | |
/* | |
* Decrypt and write the plaintext. | |
*/ | |
for( offset = 0; offset < filesize; offset += mbedtls_cipher_get_block_size( &cipher_ctx ) ) | |
{ | |
ilen = ( (unsigned int) filesize - offset > mbedtls_cipher_get_block_size( &cipher_ctx ) ) ? | |
mbedtls_cipher_get_block_size( &cipher_ctx ) : (unsigned int) ( filesize - offset ); | |
if( fread( buffer, 1, ilen, fin ) != ilen ) | |
{ | |
mbedtls_fprintf( stderr, "fread(%u bytes) failed\n", | |
mbedtls_cipher_get_block_size( &cipher_ctx ) ); | |
goto exit; | |
} | |
if( mbedtls_md_hmac_update( &md_ctx, buffer, ilen ) != 0 ) | |
{ | |
mbedtls_fprintf( stderr, "mbedtls_md_hmac_update() returned error\n" ); | |
goto exit; | |
} | |
if( mbedtls_cipher_update( &cipher_ctx, buffer, ilen, output, | |
&olen ) != 0 ) | |
{ | |
mbedtls_fprintf( stderr, "mbedtls_cipher_update() returned error\n" ); | |
goto exit; | |
} | |
if( fwrite( output, 1, olen, fout ) != olen ) | |
{ | |
mbedtls_fprintf( stderr, "fwrite(%ld bytes) failed\n", (long) olen ); | |
goto exit; | |
} | |
} | |
/* | |
* Verify the message authentication code. | |
*/ | |
if( mbedtls_md_hmac_finish( &md_ctx, digest ) != 0 ) | |
{ | |
mbedtls_fprintf( stderr, "mbedtls_md_hmac_finish() returned error\n" ); | |
goto exit; | |
} | |
if( fread( buffer, 1, mbedtls_md_get_size( md_info ), fin ) != mbedtls_md_get_size( md_info ) ) | |
{ | |
mbedtls_fprintf( stderr, "fread(%d bytes) failed\n", mbedtls_md_get_size( md_info ) ); | |
goto exit; | |
} | |
/* Use constant-time buffer comparison */ | |
diff = 0; | |
for( i = 0; i < mbedtls_md_get_size( md_info ); i++ ) | |
diff |= digest[i] ^ buffer[i]; | |
if( diff != 0 ) | |
{ | |
mbedtls_fprintf( stderr, "HMAC check failed: wrong key, " | |
"or file corrupted.\n" ); | |
goto exit; | |
} | |
/* | |
* Write the final block of data | |
*/ | |
if( mbedtls_cipher_finish( &cipher_ctx, output, &olen ) != 0 ) | |
{ | |
mbedtls_fprintf( stderr, "mbedtls_cipher_finish() returned error\n" ); | |
goto exit; | |
} | |
if( fwrite( output, 1, olen, fout ) != olen ) | |
{ | |
mbedtls_fprintf( stderr, "fwrite(%ld bytes) failed\n", (long) olen ); | |
goto exit; | |
} | |
} | |
exit_code = MBEDTLS_EXIT_SUCCESS; | |
exit: | |
if( fin ) | |
fclose( fin ); | |
if( fout ) | |
fclose( fout ); | |
/* Zeroize all memory buffers used */ | |
mbedtls_platform_zeroize( IV, sizeof( IV ) ); | |
mbedtls_platform_zeroize( key, sizeof( key ) ); | |
mbedtls_platform_zeroize( buffer, sizeof( buffer ) ); | |
mbedtls_platform_zeroize( output, sizeof( output ) ); | |
mbedtls_platform_zeroize( digest, sizeof( digest ) ); | |
mbedtls_cipher_free( &cipher_ctx ); | |
mbedtls_md_free( &md_ctx ); | |
return( exit_code ); | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment