diff --git a/pclsync/pcrypto.c b/pclsync/pcrypto.c index d407299..a779863 100644 --- a/pclsync/pcrypto.c +++ b/pclsync/pcrypto.c @@ -36,7 +36,6 @@ #include #include -#include "pfile.h" #include "pcompiler.h" #include "pssl.h" @@ -68,7 +67,7 @@ static void psync_hmac_sha512_init(psync_hmac_sha512_ctx *ctx, } psync_sha512_init(&ctx->sha1ctx); psync_sha512_update(&ctx->sha1ctx, keyxor, PSYNC_SHA512_BLOCK_LEN); - pssl_memclean(keyxor, PSYNC_SHA512_BLOCK_LEN); + putil_wipe(keyxor, PSYNC_SHA512_BLOCK_LEN); } static void psync_hmac_sha512_update(psync_hmac_sha512_ctx *ctx, @@ -81,7 +80,7 @@ static void psync_hmac_sha512_final(unsigned char *result, psync_sha512_final(ctx->final + PSYNC_SHA512_BLOCK_LEN, &ctx->sha1ctx); psync_sha512(ctx->final, PSYNC_SHA512_BLOCK_LEN + PSYNC_SHA512_DIGEST_LEN, result); - pssl_memclean(ctx->final, + putil_wipe(ctx->final, PSYNC_SHA512_BLOCK_LEN + PSYNC_SHA512_DIGEST_LEN); } @@ -107,8 +106,8 @@ static void psync_hmac_sha512(const unsigned char *msg, size_t msglen, psync_sha512_update(&sha1ctx, msg, msglen); psync_sha512_final(final + PSYNC_SHA512_BLOCK_LEN, &sha1ctx); psync_sha512(final, PSYNC_SHA512_BLOCK_LEN + PSYNC_SHA512_DIGEST_LEN, result); - pssl_memclean(keyxor, PSYNC_SHA512_BLOCK_LEN); - pssl_memclean(final, PSYNC_SHA512_BLOCK_LEN + PSYNC_SHA512_DIGEST_LEN); + putil_wipe(keyxor, PSYNC_SHA512_BLOCK_LEN); + putil_wipe(final, PSYNC_SHA512_BLOCK_LEN + PSYNC_SHA512_DIGEST_LEN); } #define ALIGN_A256_BS(n) \ @@ -193,7 +192,7 @@ pcrypto_ctr_encdec_t pcrypto_ctr_encdec_create(psync_symmetric_key_t key) { void pcrypto_ctr_encdec_free( pcrypto_ctr_encdec_t enc) { paes_free_encoder(enc->encoder); - pssl_memclean(enc->iv, PSYNC_AES256_BLOCK_SIZE); + putil_wipe(enc->iv, PSYNC_AES256_BLOCK_SIZE); psync_free(enc); } @@ -419,7 +418,7 @@ pcrypto_textenc_create(psync_symmetric_key_t key) { void pcrypto_textenc_free( pcrypto_textenc_t enc) { paes_free_encoder(enc->encoder); - pssl_memclean(enc->iv, enc->ivlen); + putil_wipe(enc->iv, enc->ivlen); pmemlock_free(enc); } @@ -445,7 +444,7 @@ pcrypto_textdec_create(psync_symmetric_key_t key) { void pcrypto_textdec_free( pcrypto_textdec_t enc) { paes_free_encoder(enc->encoder); - pssl_memclean(enc->iv, enc->ivlen); + putil_wipe(enc->iv, enc->ivlen); pmemlock_free(enc); } @@ -478,7 +477,7 @@ void pcrypto_sec_encdec_free( pcrypto_sector_encdec_t enc) { paes_free_encoder(enc->encoder); paes_free_decoder(enc->decoder); - pssl_memclean(enc->iv, enc->ivlen); + putil_wipe(enc->iv, enc->ivlen); pmemlock_free(enc); } diff --git a/pclsync/pcryptofolder.c b/pclsync/pcryptofolder.c index d51a142..c9603c9 100644 --- a/pclsync/pcryptofolder.c +++ b/pclsync/pcryptofolder.c @@ -634,7 +634,7 @@ int pcryptofolder_unlock(const char *password) { debug(D_NOTICE, "trying to load private key"); crypto_privkey = prsa_load_private(rsaprivdec, rsaprivlen); - pssl_memclean(rsaprivdec, rsaprivlen); + putil_wipe(rsaprivdec, rsaprivlen); pmemlock_free(rsaprivdec); if (crypto_privkey == PSYNC_INVALID_RSA) { debug(D_NOTICE, "failed to load private key"); @@ -1704,7 +1704,7 @@ char *pcryptofolder_filencoder_key_new(uint32_t flags, size_t *keylen) { debug(D_ERROR, "RSA encryption failed"); return (char *)errptr(PRINT_RETURN_CONST(PSYNC_CRYPTO_RSA_ERROR)); } - pssl_memclean(&sym, sizeof(sym)); + putil_wipe(&sym, sizeof(sym)); ret = (char *)psync_base64_encode(encsym->data, encsym->datalen, keylen); psync_free(encsym); return ret; @@ -1734,7 +1734,7 @@ char *pcryptofolder_filencoder_key_newplain( return (char *)errptr(PRINT_RETURN_CONST(PSYNC_CRYPTO_RSA_ERROR)); } *deckey = symkeyv1_to_symkey(&sym); - pssl_memclean(&sym, sizeof(sym)); + putil_wipe(&sym, sizeof(sym)); ret = (char *)psync_base64_encode(encsym->data, encsym->datalen, keylen); psync_free(encsym); return ret; @@ -1762,7 +1762,7 @@ int pcryptofolder_mkdir(psync_folderid_t folderid, const char *name, } encsym = prsa_encrypt_data(crypto_pubkey, (unsigned char *)&sym, sizeof(sym)); - pssl_memclean(&sym, sizeof(sym)); + putil_wipe(&sym, sizeof(sym)); ret = get_fldr_name(folderid, name, &ename, err); pthread_rwlock_unlock(&crypto_lock); if (ret) { @@ -1864,7 +1864,7 @@ int psync_pcloud_crypto_reencode_key( pcrypto_ctr_encdec_free(enc); newprivlen = offsetof(priv_key_ver1, key) + rsaprivlen; priv = prsa_load_private(rsaprivdec, rsaprivlen); - pssl_memclean(rsaprivdec, rsaprivlen); + putil_wipe(rsaprivdec, rsaprivlen); psync_free(rsaprivdec); if (unlikely(priv == PSYNC_INVALID_RSA)) goto err_ph_1; diff --git a/pclsync/ppassword.c b/pclsync/ppassword.c index 704617c..8a471b2 100644 --- a/pclsync/ppassword.c +++ b/pclsync/ppassword.c @@ -39,6 +39,7 @@ #include "ppassword.h" #include "ppassworddict.h" #include "pssl.h" +#include "putil.h" #include #include @@ -351,8 +352,8 @@ uint64_t ppassword_score(const char *cpassword) { ldpwd[nlen] = lpwd[nlen]; } num = score_variants(password, lpwd, ldpwd, plen); - pssl_memclean(lpwd, plen); - pssl_memclean(ldpwd, plen); + putil_wipe(lpwd, plen); + putil_wipe(ldpwd, plen); psync_free(lpwd); psync_free(ldpwd); mul_score(num); diff --git a/pclsync/pssl.c b/pclsync/pssl.c index c9fa996..1b6bd88 100644 --- a/pclsync/pssl.c +++ b/pclsync/pssl.c @@ -58,6 +58,7 @@ #include "pssl.h" #include "psslcerts.h" #include "psynclib.h" +#include "putil.h" static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; @@ -69,7 +70,7 @@ static void ssl_debug(int loglevel, int errnum, const char *msg) { } static void free_encrypted(psync_encrypted_data_t e) { - pssl_memclean(e->data, e->datalen); + putil_wipe(e->data, e->datalen); pmemlock_free(e); } @@ -78,7 +79,7 @@ void prsa_free_binary(psync_binary_rsa_key_t bin) { } void psymkey_free(psync_symmetric_key_t key) { - pssl_memclean(key->key, key->keylen); + putil_wipe(key->key, key->keylen); pmemlock_free(key); } @@ -207,12 +208,6 @@ int pssl_init() { return 0; } -void pssl_memclean(void *ptr, size_t len) { - volatile unsigned char *p = ptr; - while (len--) - *p++ = 0; -} - static ssl_connection_t *conn_alloc(const char *hostname) { ssl_connection_t *conn; size_t len; @@ -574,7 +569,7 @@ prsa_private_to_binary(psync_rsa_privatekey_t rsa) { pmemlock_malloc(offsetof(psync_encrypted_data_struct_t, data) + len); ret->datalen = len; memcpy(ret->data, buff + sizeof(buff) - len, len); - pssl_memclean(buff + sizeof(buff) - len, len); + putil_wipe(buff + sizeof(buff) - len, len); return ret; } @@ -754,7 +749,7 @@ psync_symmetric_key_t prsa_decrypt_data(psync_rsa_privatekey_t rsa, offsetof(psync_symmetric_key_struct_t, key) + len); ret->keylen = len; memcpy(ret->key, buff, len); - pssl_memclean(buff, len); + putil_wipe(buff, len); return ret; } @@ -779,7 +774,7 @@ paes_create_encoder(psync_symmetric_key_t key) { } void paes_free_encoder(psync_aes256_encoder aes) { - pssl_memclean(aes, sizeof(mbedtls_aes_context)); + putil_wipe(aes, sizeof(mbedtls_aes_context)); psync_free(aes); } @@ -793,7 +788,7 @@ paes_create_decoder(psync_symmetric_key_t key) { } void paes_free_decoder(psync_aes256_encoder aes) { - pssl_memclean(aes, sizeof(mbedtls_aes_context)); + putil_wipe(aes, sizeof(mbedtls_aes_context)); psync_free(aes); } diff --git a/pclsync/pssl.h b/pclsync/pssl.h index 0e7921d..6d8a2fb 100644 --- a/pclsync/pssl.h +++ b/pclsync/pssl.h @@ -149,7 +149,6 @@ typedef psync_encrypted_data_t psync_rsa_signature_t; // Lock used to serialize access to RSA decrypt key function int pssl_init(); -void pssl_memclean(void *ptr, size_t len); int pssl_connect(int sock, void **sslconn, const char *hostname); int pssl_connect_finish(void *sslconn, const char *hostname); void pssl_free(void *sslconn); diff --git a/pclsync/putil.c b/pclsync/putil.c new file mode 100644 index 0000000..04c4ff4 --- /dev/null +++ b/pclsync/putil.c @@ -0,0 +1,35 @@ +#include +#include +#include +#include + +#include "plibs.h" + +// wipe a segment of memory mem of size sz using a DoD 5220.22-M compliant +// 3-pass wipe. the first pass overwrites the memory with zeroes, the second +// with ones, and the third with random data using the urandom entropy +// source. if the urandom source fails, it falls back to a simple +// (non-cryptographically-secure) RNG. +void putil_wipe(void *mem, size_t sz) { + if (!mem || sz == 0) { return; } + + volatile unsigned char *p = (volatile unsigned char *)mem; + + memset((void*)p, 0x00, sz); + memset((void*)p, 0xFF, sz); + + ssize_t result = getrandom((void*)p, sz, 0); + if (result != (ssize_t)sz) { + if (result == -1) { + debug(D_WARNING, "getrandom() failed: %s.", strerror(errno)); + } else { + debug(D_WARNING, "getrandom() returned partial data."); + } + + debug(D_WARNING, "falling back to less secure third pass. This may occur due to insufficient entropy, early boot state, or kernel incompatibility."); + srand((unsigned int)(time(NULL) ^ (uintptr_t)&srand)); + for (size_t i = 0; i < sz; i++) { + p[i] = (unsigned char)rand(); + } + } +} diff --git a/pclsync/putil.h b/pclsync/putil.h index 157d6fc..a956188 100644 --- a/pclsync/putil.h +++ b/pclsync/putil.h @@ -1,3 +1,12 @@ +#ifndef __PUTIL_H +#define __PUTIL_H + +#include + #define NTO_STR(s) TO_STR(s) #define TO_STR(s) #s #define VAR_ARRAY(name, type, size) type name[size] + +void putil_wipe(void *mem, size_t sz); + +#endif