/* Compute MD5 hash on in and store the base64 string result in out. */ void md5_base64(char *out, unsigned char *in, size_t size) { uint8_t md[MD5_DIGEST_LEN]; md5(md, in, size); b64_encode(md, out, MD5_DIGEST_LEN); strip_b64_eq(out); }
/* Compute SHA512 hash on in and store the base64 string result in out. */ void sha512_base64(char *out, unsigned char *in, size_t size) { uint8_t md[SHA512_DIGEST_LEN]; sha512(md, in, size); b64_encode(md, out, SHA512_DIGEST_LEN); strip_b64_eq(out); }
/* Prep and encrypt using Rijndael */ static int _rijndael_encrypt(fko_ctx_t ctx, const char *enc_key) { char *plain; char *b64cipher; unsigned char *cipher; int cipher_len; /* Make a bucket big enough to hold the enc msg + digest (plaintext) * and populate it appropriately. */ plain = malloc(strlen(ctx->encoded_msg) + strlen(ctx->digest) + 4); if(plain == NULL) return(FKO_ERROR_MEMORY_ALLOCATION); snprintf(plain, strlen(ctx->encoded_msg) + strlen(ctx->digest) + 4, "%s:%s", ctx->encoded_msg, ctx->digest); /* Make a bucket for the encrypted version and populate it. */ cipher = malloc(strlen(plain) + 32); /* Plus padding for salt and Block */ if(cipher == NULL) return(FKO_ERROR_MEMORY_ALLOCATION); cipher_len = rij_encrypt( (unsigned char*)plain, strlen(plain), (char*)enc_key, cipher ); /* Now make a bucket for the base64-encoded version and populate it. */ b64cipher = malloc(((cipher_len / 3) * 4) + 8); if(b64cipher == NULL) return(FKO_ERROR_MEMORY_ALLOCATION); b64_encode(cipher, b64cipher, cipher_len); strip_b64_eq(b64cipher); ctx->encrypted_msg = strdup(b64cipher); /* Clean-up */ free(plain); free(cipher); free(b64cipher); if(ctx->encrypted_msg == NULL) return(FKO_ERROR_MEMORY_ALLOCATION); return(FKO_SUCCESS); }
/* Take a given string, base64-encode it and append it to the given * buffer. */ static int append_b64(char* tbuf, char *str) { int len = strlen(str); char *bs; bs = malloc(((len/3)*4)+8); if(bs == NULL) return(FKO_ERROR_MEMORY_ALLOCATION); b64_encode((unsigned char*)str, bs, len); /* --DSS XXX: make sure to check here if later decoding * becomes a problem. */ strip_b64_eq(bs); strlcat(tbuf, bs, FKO_ENCODE_TMP_BUF_SIZE); free(bs); return(FKO_SUCCESS); }
int fko_set_spa_hmac(fko_ctx_t ctx, const char * const hmac_key, const int hmac_key_len) { unsigned char hmac[SHA512_DIGEST_STR_LEN] = {0}; char *hmac_base64 = NULL; int hmac_digest_str_len = 0; int hmac_digest_len = 0; /* Must be initialized */ if(!CTX_INITIALIZED(ctx)) return(FKO_ERROR_CTX_NOT_INITIALIZED); if(hmac_key_len > MAX_DIGEST_BLOCK_LEN) return(FKO_ERROR_INVALID_HMAC_KEY_LEN); if(ctx->hmac_type == FKO_HMAC_MD5) { hmac_md5(ctx->encrypted_msg, ctx->encrypted_msg_len, hmac, hmac_key, hmac_key_len); hmac_digest_len = MD5_DIGEST_LEN; hmac_digest_str_len = MD5_DIGEST_STR_LEN; } else if(ctx->hmac_type == FKO_HMAC_SHA1) { hmac_sha1(ctx->encrypted_msg, ctx->encrypted_msg_len, hmac, hmac_key, hmac_key_len); hmac_digest_len = SHA1_DIGEST_LEN; hmac_digest_str_len = SHA1_DIGEST_STR_LEN; } else if(ctx->hmac_type == FKO_HMAC_SHA256) { hmac_sha256(ctx->encrypted_msg, ctx->encrypted_msg_len, hmac, hmac_key, hmac_key_len); hmac_digest_len = SHA256_DIGEST_LEN; hmac_digest_str_len = SHA256_DIGEST_STR_LEN; } else if(ctx->hmac_type == FKO_HMAC_SHA384) { hmac_sha384(ctx->encrypted_msg, ctx->encrypted_msg_len, hmac, hmac_key, hmac_key_len); hmac_digest_len = SHA384_DIGEST_LEN; hmac_digest_str_len = SHA384_DIGEST_STR_LEN; } else if(ctx->hmac_type == FKO_HMAC_SHA512) { hmac_sha512(ctx->encrypted_msg, ctx->encrypted_msg_len, hmac, hmac_key, hmac_key_len); hmac_digest_len = SHA512_DIGEST_LEN; hmac_digest_str_len = SHA512_DIGEST_STR_LEN; } hmac_base64 = calloc(1, MD_HEX_SIZE(hmac_digest_len)+1); if (hmac_base64 == NULL) return(FKO_ERROR_MEMORY_ALLOCATION); b64_encode(hmac, hmac_base64, hmac_digest_len); strip_b64_eq(hmac_base64); if(ctx->msg_hmac != NULL) free(ctx->msg_hmac); ctx->msg_hmac = strdup(hmac_base64); ctx->msg_hmac_len = strnlen(ctx->msg_hmac, hmac_digest_str_len); free(hmac_base64); switch(ctx->msg_hmac_len) { case MD5_B64_LEN: break; case SHA1_B64_LEN: break; case SHA256_B64_LEN: break; case SHA384_B64_LEN: break; case SHA512_B64_LEN: break; default: return(FKO_ERROR_INVALID_DATA_HMAC_LEN_VALIDFAIL); } return FKO_SUCCESS; }
/* Prep and encrypt using gpgme */ static int gpg_encrypt(fko_ctx_t ctx, const char *enc_key) { int res; char *plain; char *b64cipher; unsigned char *cipher = NULL; size_t cipher_len; /* First make sure we have a recipient key set. */ if(ctx->gpg_recipient == NULL) return(FKO_ERROR_MISSING_GPG_KEY_DATA); /* Make a bucket big enough to hold the enc msg + digest (plaintext) * and populate it appropriately. */ plain = malloc(strlen(ctx->encoded_msg) + strlen(ctx->digest) + 2); if(plain == NULL) return(FKO_ERROR_MEMORY_ALLOCATION); snprintf(plain, strlen(ctx->encoded_msg) + strlen(ctx->digest) + 2, "%s:%s", ctx->encoded_msg, ctx->digest); res = gpgme_encrypt(ctx, (unsigned char*)plain, strlen(plain), enc_key, &cipher, &cipher_len ); /* --DSS XXX: Better parsing of what went wrong would be nice :) */ if(res != FKO_SUCCESS) { free(plain); if(cipher) free(cipher); return(res); } /* Now make a bucket for the base64-encoded version and populate it. */ b64cipher = malloc(((cipher_len / 3) * 4) + 8); if(b64cipher == NULL) return(FKO_ERROR_MEMORY_ALLOCATION); b64_encode(cipher, b64cipher, cipher_len); strip_b64_eq(b64cipher); ctx->encrypted_msg = strdup(b64cipher); /* Clean-up */ free(plain); free(cipher); free(b64cipher); if(ctx->encrypted_msg == NULL) return(FKO_ERROR_MEMORY_ALLOCATION); return(FKO_SUCCESS); }
/* Prep and encrypt using Rijndael */ static int _rijndael_encrypt(fko_ctx_t ctx, const char *enc_key, const int enc_key_len) { char *plaintext; char *b64ciphertext; unsigned char *ciphertext; int cipher_len; int pt_len; int zero_free_rv = FKO_SUCCESS; if(enc_key_len > RIJNDAEL_MAX_KEYSIZE) return(FKO_ERROR_INVALID_KEY_LEN); if (! is_valid_encoded_msg_len(ctx->encoded_msg_len)) return(FKO_ERROR_INVALID_DATA_ENCRYPT_MSGLEN_VALIDFAIL); switch(ctx->digest_len) { case MD5_B64_LEN: break; case SHA1_B64_LEN: break; case SHA256_B64_LEN: break; case SHA384_B64_LEN: break; case SHA512_B64_LEN: break; default: return(FKO_ERROR_INVALID_DATA_ENCRYPT_DIGESTLEN_VALIDFAIL); } pt_len = ctx->encoded_msg_len + ctx->digest_len + RIJNDAEL_BLOCKSIZE + 2; /* Make a bucket big enough to hold the enc msg + digest (plaintext) * and populate it appropriately. */ plaintext = calloc(1, pt_len); if(plaintext == NULL) return(FKO_ERROR_MEMORY_ALLOCATION); pt_len = snprintf(plaintext, pt_len, "%s:%s", ctx->encoded_msg, ctx->digest); if(! is_valid_pt_msg_len(pt_len)) { if(zero_free(plaintext, pt_len) == FKO_SUCCESS) return(FKO_ERROR_INVALID_DATA_ENCRYPT_PTLEN_VALIDFAIL); else return(FKO_ERROR_ZERO_OUT_DATA); } /* Make a bucket for the encrypted version and populate it. */ ciphertext = calloc(1, pt_len + 32); /* Plus padding for salt and Block */ if(ciphertext == NULL) { if(zero_free(plaintext, pt_len) == FKO_SUCCESS) return(FKO_ERROR_MEMORY_ALLOCATION); else return(FKO_ERROR_ZERO_OUT_DATA); } cipher_len = rij_encrypt( (unsigned char*)plaintext, pt_len, (char*)enc_key, enc_key_len, ciphertext, ctx->encryption_mode ); /* Now make a bucket for the base64-encoded version and populate it. */ b64ciphertext = malloc(((cipher_len / 3) * 4) + 8); if(b64ciphertext == NULL) { if(zero_free((char *) ciphertext, pt_len+32) == FKO_SUCCESS && zero_free(plaintext, pt_len) == FKO_SUCCESS) return(FKO_ERROR_MEMORY_ALLOCATION); else return(FKO_ERROR_ZERO_OUT_DATA); } b64_encode(ciphertext, b64ciphertext, cipher_len); strip_b64_eq(b64ciphertext); if(ctx->encrypted_msg != NULL) zero_free_rv = zero_free(ctx->encrypted_msg, strnlen(ctx->encrypted_msg, MAX_SPA_ENCODED_MSG_SIZE)); ctx->encrypted_msg = strdup(b64ciphertext); ctx->encrypted_msg_len = strnlen(ctx->encrypted_msg, MAX_SPA_ENCODED_MSG_SIZE); /* Clean-up */ if(zero_free(plaintext, pt_len) != FKO_SUCCESS) zero_free_rv = FKO_ERROR_ZERO_OUT_DATA; if(zero_free((char *) ciphertext, pt_len+32) != FKO_SUCCESS) zero_free_rv = FKO_ERROR_ZERO_OUT_DATA; if(zero_free(b64ciphertext, strnlen(b64ciphertext, MAX_SPA_ENCODED_MSG_SIZE)) != FKO_SUCCESS) zero_free_rv = FKO_ERROR_ZERO_OUT_DATA; if(ctx->encrypted_msg == NULL) return(FKO_ERROR_MEMORY_ALLOCATION); if(! is_valid_encoded_msg_len(ctx->encrypted_msg_len)) return(FKO_ERROR_INVALID_DATA_ENCRYPT_RESULT_MSGLEN_VALIDFAIL); return(zero_free_rv); }
/* Prep and encrypt using gpgme */ static int gpg_encrypt(fko_ctx_t ctx, const char *enc_key) { int res; char *plain; int pt_len, zero_free_rv = FKO_SUCCESS; char *b64cipher; unsigned char *cipher = NULL; size_t cipher_len; char *empty_key = ""; if (! is_valid_encoded_msg_len(ctx->encoded_msg_len)) return(FKO_ERROR_INVALID_DATA_ENCRYPT_GPG_MESSAGE_VALIDFAIL); switch(ctx->digest_len) { case MD5_B64_LEN: break; case SHA1_B64_LEN: break; case SHA256_B64_LEN: break; case SHA384_B64_LEN: break; case SHA512_B64_LEN: break; default: return(FKO_ERROR_INVALID_DATA_ENCRYPT_GPG_DIGEST_VALIDFAIL); } /* First make sure we have a recipient key set. */ if(ctx->gpg_recipient == NULL) return(FKO_ERROR_MISSING_GPG_KEY_DATA); pt_len = ctx->encoded_msg_len + ctx->digest_len + 2; /* Make a bucket big enough to hold the enc msg + digest (plaintext) * and populate it appropriately. */ plain = malloc(ctx->encoded_msg_len + ctx->digest_len + 2); if(plain == NULL) return(FKO_ERROR_MEMORY_ALLOCATION); pt_len = snprintf(plain, pt_len+1, "%s:%s", ctx->encoded_msg, ctx->digest); if(! is_valid_pt_msg_len(pt_len)) { if(zero_free(plain, pt_len) == FKO_SUCCESS) return(FKO_ERROR_INVALID_DATA_ENCRYPT_GPG_MSGLEN_VALIDFAIL); else return(FKO_ERROR_ZERO_OUT_DATA); } if (enc_key != NULL) { res = gpgme_encrypt(ctx, (unsigned char*)plain, pt_len, enc_key, &cipher, &cipher_len ); } else { res = gpgme_encrypt(ctx, (unsigned char*)plain, pt_len, empty_key, &cipher, &cipher_len ); } /* --DSS XXX: Better parsing of what went wrong would be nice :) */ if(res != FKO_SUCCESS) { zero_free_rv = zero_free(plain, pt_len); if(cipher != NULL) if(zero_free((char *) cipher, cipher_len) != FKO_SUCCESS) zero_free_rv = FKO_ERROR_ZERO_OUT_DATA; if(zero_free_rv == FKO_SUCCESS) return(res); else return(zero_free_rv); } /* Now make a bucket for the base64-encoded version and populate it. */ b64cipher = malloc(((cipher_len / 3) * 4) + 8); if(b64cipher == NULL) { if(zero_free(plain, pt_len) != FKO_SUCCESS) zero_free_rv = FKO_ERROR_ZERO_OUT_DATA; if(cipher != NULL) if(zero_free((char *) cipher, cipher_len) != FKO_SUCCESS) zero_free_rv = FKO_ERROR_ZERO_OUT_DATA; if(zero_free_rv == FKO_SUCCESS) return(FKO_ERROR_MEMORY_ALLOCATION); else return(zero_free_rv); } b64_encode(cipher, b64cipher, cipher_len); strip_b64_eq(b64cipher); if(ctx->encrypted_msg != NULL) zero_free_rv = zero_free(ctx->encrypted_msg, strnlen(ctx->encrypted_msg, MAX_SPA_ENCODED_MSG_SIZE)); ctx->encrypted_msg = strdup(b64cipher); ctx->encrypted_msg_len = strnlen(ctx->encrypted_msg, MAX_SPA_ENCODED_MSG_SIZE); /* Clean-up */ if(zero_free(plain, pt_len) != FKO_SUCCESS) zero_free_rv = FKO_ERROR_ZERO_OUT_DATA; if(zero_free((char *) cipher, cipher_len) != FKO_SUCCESS) zero_free_rv = FKO_ERROR_ZERO_OUT_DATA; if(zero_free(b64cipher, strnlen(b64cipher, MAX_SPA_ENCODED_MSG_SIZE)) != FKO_SUCCESS) zero_free_rv = FKO_ERROR_ZERO_OUT_DATA; if(ctx->encrypted_msg == NULL) return(FKO_ERROR_MEMORY_ALLOCATION); if(! is_valid_encoded_msg_len(ctx->encrypted_msg_len)) return(FKO_ERROR_INVALID_DATA_ENCRYPT_GPG_RESULT_MSGLEN_VALIDFAIL); return(zero_free_rv); }