Преглед изворни кода

AES encrypted QR codes instead of one time pads

clementinecomputing пре 4 година
родитељ
комит
ea9e6841af
2 измењених фајлова са 291 додато и 4 уклоњено
  1. 284 4
      busunit/passdb/fareqr.c
  2. 7 0
      busunit/passdb/fareqr.h

+ 284 - 4
busunit/passdb/fareqr.c

@@ -20,6 +20,235 @@
 
 #include "fareqr.h"
 
+// AES CBC, sha256 message digest, with salt.
+// Functions modified from https://wiki.openssl.org/index.php/EVP_Symmetric_Encryption_and_Decryption
+//
+// openssl example commands to encrypt/decrypt:
+// msg=";123456789012345?"
+// key="oovevobie8woid1Ou3iu6aboochei2AeKoceeCh1iePheuRae4Yai1dahtheegi7"
+// openssl enc -aes-256-cbc -in <( echo -n "$msg" ) -out /dev/stdout -pass pass:"$key" -e -base64 -md sha256
+//
+// ---
+//
+// to descypt with openssl
+//
+// openssl aes-256-cbc -d -a  -in <( echo "U2FsdGVkX19gpKzk+Y5SGgnQr1uwpUYUpea6nu77wJfG6bD4GZpRneSaxaallz0n" ) -out /dev/stdout -pass pass:"$key" -md sha256
+//
+
+
+static int aes_encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key, unsigned char *iv, unsigned char *ciphertext) {
+  EVP_CIPHER_CTX *ctx;
+
+  int len;
+
+  int ciphertext_len;
+
+  // Create and initialise the context
+  if(!(ctx = EVP_CIPHER_CTX_new())) { return -1; }
+
+  // Initialise the encryption operation. IMPORTANT - ensure you use a key
+  // and IV size appropriate for your cipher
+  // In this example we are using 256 bit AES (i.e. a 256 bit key). The
+  // IV size for *most* modes is the same as the block size. For AES this
+  // is 128 bits
+  //
+  if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv)) { return -2; }
+
+  // Provide the message to be encrypted, and obtain the encrypted output.
+  // EVP_EncryptUpdate can be called multiple times if necessary
+  //
+  if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len)) { return -3; }
+  ciphertext_len = len;
+
+  // Finalise the encryption. Further ciphertext bytes may be written at
+  // this stage.
+  //
+  if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) { return -4; }
+  ciphertext_len += len;
+
+  // Clean up
+  //
+  EVP_CIPHER_CTX_free(ctx);
+
+  return ciphertext_len;
+}
+
+static int aes_decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key, unsigned char *iv, unsigned char *plaintext) {   
+  EVP_CIPHER_CTX *ctx;
+  int plaintext_len, len;
+
+  // Create and initialise the context
+  //
+  if(!(ctx = EVP_CIPHER_CTX_new())) { return -1; }
+
+  // Initialise the decryption operation. IMPORTANT - ensure you use a key
+  // and IV size appropriate for your cipher
+  // In this example we are using 256 bit AES (i.e. a 256 bit key). The
+  // IV size for *most* modes is the same as the block size. For AES this
+  // is 128 bits
+  //
+  if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv)) { return -2; }
+
+  // Provide the message to be decrypted, and obtain the plaintext output.
+  // EVP_DecryptUpdate can be called multiple times if necessary.
+  //
+  if(1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len)) { return -3; }
+  plaintext_len = len;
+
+  // Finalise the decryption. Further plaintext bytes may be written at
+  // this stage.
+  //
+  if(1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len)) { return -4; }
+  plaintext_len += len;
+
+  // Clean up
+  //
+  EVP_CIPHER_CTX_free(ctx);
+
+  return plaintext_len;
+}
+
+// Helper function to take secret key/pass (pass_key) and the encoded
+// base64 string and decrypt it with AES CBC 256, sha256 message digest.
+// 
+// return the number of bytes decoded on success
+// return non-positive number on error
+//
+static int decode_b64(unsigned char *decrypt_text,
+                      unsigned char *pass_key,
+                      unsigned char *enc_b64) {
+  int i=0, _ret = 0, r=0;
+  unsigned char *enc_b = NULL, salt[8];
+  unsigned char *key = NULL, *iv = NULL, *ciphertext_b = NULL;
+  size_t b64_sz=0, enc_len=0, enc_size=0, ciphertext_len;
+
+  if ((!decrypt_text) || (!pass_key) || (!enc_b64)) { return -9; }
+
+  enc_size = Base64decode_len(enc_b64);
+  if (enc_size < 1) {
+    _ret=-1;
+    goto _decode_b64_cleanup;
+  }
+
+  enc_b = (unsigned char *)calloc(enc_size, sizeof(char));
+  if (!enc_b) {
+    _ret=-2;
+    goto _decode_b64_cleanup;
+  }
+  Base64decode(enc_b, enc_b64);
+  enc_len = enc_size-1;
+
+  // Check exmpanded string is well formed (has "Salted__" prefix, etc.)
+  // and extract the salt
+  //
+  if (enc_len < 16) {
+    _ret = -3;
+    goto _decode_b64_cleanup;
+  }
+  if (strncmp(enc_b, "Salted__", 8)!=0) {
+    _ret = -4;
+    goto _decode_b64_cleanup;
+  }
+  for (i=0; i<8; i++) { salt[i] = enc_b[i+8]; }
+
+  // Move past the salt prefix 8 bytes) and 8 bytes of salt
+  //
+  ciphertext_b    = enc_b   + 16;
+  ciphertext_len  = enc_len - 16;
+
+  // Allocate iv, key and extract them from the salt and pass phrase
+  //
+  iv  = (unsigned char *)calloc(256, sizeof(char));
+  key = (unsigned char *)calloc(256, sizeof(char));
+  r = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha256(), salt, pass_key, strlen(pass_key), 1, key, iv);
+  if (!r) {
+    _ret = -5;
+    goto _decode_b64_cleanup;
+  }
+
+
+  r = aes_decrypt(ciphertext_b, ciphertext_len, key, iv, decrypt_text);
+  if (r<=0) {
+    _ret = -6;
+    goto _decode_b64_cleanup;
+  }
+
+  decrypt_text[r] = '\0';
+  _ret = r;
+
+_decode_b64_cleanup:
+
+  if (enc_b) { free(enc_b); }
+  if (key) { free(key); }
+  if (iv) { free(iv); }
+
+  return _ret;
+}
+
+static int encode_b64(unsigned char *enc_b64,
+                      unsigned char *pass_key,
+                      unsigned char *msg) {
+  int i=0, _ret = 0, r=0;
+  unsigned char *enc_b = NULL;
+  unsigned char *key = NULL, *iv = NULL, *ciphertext_b = NULL;
+  size_t b64_sz=0, enc_len=0, enc_size=0, ciphertext_len;
+
+  unsigned char salt[8];
+  char _pfx[] = "Salted__";
+
+  if ((!enc_b64) || (!pass_key) || (!msg)) { return -9; }
+
+  for (i=0; i<8; i++) { salt[i] = (unsigned char)(rand() % 256); }
+
+  iv  = (unsigned char *)calloc(256, sizeof(char));
+  key = (unsigned char *)calloc(256, sizeof(char));
+  r = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha256(), salt, pass_key, strlen(pass_key), 1, key, iv);
+  if (!r) {
+    _ret = -5;
+    goto _encode_b64_cleanup;
+  }
+
+  enc_b = (unsigned char *)calloc(2*LINE_BUFFER_SIZE, sizeof(char));
+  if (!enc_b) {
+    _ret = -4;
+    goto _encode_b64_cleanup;
+  }
+
+  for (i=0; i<8; i++) {
+    enc_b[i] = _pfx[i];
+    enc_b[i+8] = salt[i];
+  }
+
+  enc_len = aes_encrypt(msg, strlen(msg), key, iv, enc_b+16);
+  if (enc_len<=0) {
+    _ret = -6;
+    goto _encode_b64_cleanup;
+  }
+  enc_len += 16;
+
+  b64_sz = Base64encode_len(enc_len);
+  Base64encode(enc_b64, enc_b, enc_len);
+  _ret = b64_sz;
+
+_encode_b64_cleanup:
+
+  if (enc_b) { free(enc_b); }
+  if (key) { free(key); }
+  if (iv) { free(iv); }
+
+  return _ret;
+}
+
+
+
+// `fqreqr_lookup_decode` uses the public key portion of `fareqr_s`
+// to lookup the private pass/key in the file `seedfn`.
+// If found, it then proceeds to decrypt and store the encrypted
+// credential in `dst_cred`
+//
+// returns 0 on success
+// returns non zero on error
+// 
 int fareqr_lookup_decode(char *seedfn, char *fareqr_s, char *dst_cred) {
   int i, n, r, _ret = 0;;
   char *p=NULL, *stop_tok=NULL;
@@ -51,7 +280,8 @@ int fareqr_lookup_decode(char *seedfn, char *fareqr_s, char *dst_cred) {
   r = fareqr_lookup_seed_secret(seedfn, pub_key, priv_key);
   if (r<0) { _ret = r; }
   else {
-    r = fareqr_decode(fareqr_s, pub_key, priv_key, dst_cred);
+    //r = fareqr_decode(fareqr_s, pub_key, priv_key, dst_cred);
+    r = decode_b64(dst_cred, priv_key, enc_str);
     if (r<0) { _ret = r; }
   }
 
@@ -64,6 +294,8 @@ int fareqr_lookup_decode(char *seedfn, char *fareqr_s, char *dst_cred) {
   return _ret;
 }
 
+// depreicated (doing away with one-time pads in favor of AES above)
+//
 int fareqr_encode(char *tok_public, char *tok_secret, char *tok_cred, char *fareqr_str) {
   int i, r;
   uint8_t x,y,z;
@@ -106,6 +338,8 @@ int fareqr_encode(char *tok_public, char *tok_secret, char *tok_cred, char *fare
 }
 
 
+// depreicated (doing away with one-time pads in favor of AES above)
+//
 int fareqr_decode(char *fareqr_s, char *check_pub, char *tok_secret, char *dst_cred) {
   int i, n, _ret=0;
   char *p, *stop_tok;
@@ -273,11 +507,11 @@ void show_help(FILE *ofp) {
   fprintf(ofp, "Here is some example usage:\n");
   fprintf(ofp, "\n");
   fprintf(ofp, "  $ fareqr encode 'wu9XouSh' 'ohNgizahkephain3aosoh2AeH1aethoo4cie6oiSaezimaighai2eiVaefahfien' ';123456789060535?'\n");
-  fprintf(ofp, "  @wu9XouSh%VFl8VF1PV19TXEBeUVxdBl4=\n");
-  fprintf(ofp, "  $ fareqr decode 'ohNgizahkephain3aosoh2AeH1aethoo4cie6oiSaezimaighai2eiVaefahfien' '@wu9XouSh%VFl8VF1PV19TXEBeUVxdBl4=$'\n");
+  fprintf(ofp, "  @wu9XouSh%%VFl8VF1PV19TXEBeUVxdBl4=\n");
+  fprintf(ofp, "  $ fareqr decode 'ohNgizahkephain3aosoh2AeH1aethoo4cie6oiSaezimaighai2eiVaefahfien' '@wu9XouSh%%VFl8VF1PV19TXEBeUVxdBl4=$'\n");
   fprintf(ofp, "  ;123456789060535?\n");
   fprintf(ofp, "  $ echo 'wu9XouSh ohNgizahkephain3aosoh2AeH1aethoo4cie6oiSaezimaighai2eiVaefahfien' > ./qr.seed\n");
-  fprintf(ofp, "  $ fareqr dbdecode ./qr.seed '@wu9XouSh%VFl8VF1PV19TXEBeUVxdBl4=$'\n");
+  fprintf(ofp, "  $ fareqr dbdecode ./qr.seed '@wu9XouSh%%VFl8VF1PV19TXEBeUVxdBl4=$'\n");
   fprintf(ofp, "  ;123456789060535?\n");
   fprintf(ofp, "\n");
   fprintf(ofp, "Where 'wu9XouSh' is the public key, 'ohNgizahkephain3aosoh2AeH1aethoo4cie6oiSaezimaighai2eiVaefahfien' is the private key and\n");
@@ -386,6 +620,52 @@ int main(int argc, char **argv) {
 
   }
 
+  // test out our AES encryption
+  //
+  else if (strcmp(argv[1], "aes-decode")==0) {
+    if (argc>2) {
+      tok_secret = strdup(argv[2]);
+      if (argc>3) {
+        fareqr_str = strdup(argv[3]);
+      }
+    }
+
+
+    tok_cred = (unsigned char *)calloc(LINE_BUFFER_SIZE, sizeof(char));
+    r = decode_b64(tok_cred, tok_secret, fareqr_str);
+    if (r<0) {
+      fprintf(stderr, "could not decode aes base64 string (AES CBC 256, sha256 md) (got %i)\n", r);
+    }
+    else {
+      printf("%s\n", tok_cred);
+    }
+
+  }
+
+  // test out our AES encryption
+  //
+  else if (strcmp(argv[1], "aes-encode")==0) {
+    if (argc>2) {
+      tok_secret = strdup(argv[2]);
+      if (argc>3) {
+        tok_cred = strdup(argv[3]);
+      }
+    }
+
+    printf(">>> '%s' '%s'\n", tok_secret, tok_cred);
+
+
+    fareqr_str = (unsigned char *)calloc(2*LINE_BUFFER_SIZE, sizeof(char));
+    r = encode_b64(fareqr_str, tok_secret, tok_cred);
+    if (r<0) {
+      fprintf(stderr, "could not encode aes base64 string (AES CBC 256, sha256 md) (got %i)\n", r);
+    }
+    else {
+      printf("%s\n", fareqr_str);
+    }
+
+  }
+
   else if (strcmp(argv[1], "help")==0) {
     show_help(stdout);
     exit(0);

+ 7 - 0
busunit/passdb/fareqr.h

@@ -27,6 +27,13 @@
 #include <string.h>
 #include <stdint.h>
 
+#include <openssl/conf.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
+#include <ctype.h>
+
+#include "b64.h"
+
 #include "../common/common_config.h"
 
 #include "b64.h"