remove pssl-{openssl,securetransport}.c
This commit is contained in:
parent
2e702d8d4e
commit
4a70d57cd3
|
|
@ -1,989 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2013 Anton Titov.
|
||||
|
||||
Copyright (c) 2013 pCloud Ltd. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met: Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer. Redistributions in binary form must reproduce the
|
||||
above copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution. Neither the name of pCloud Ltd nor the
|
||||
names of its contributors may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL pCloud
|
||||
Ltd BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGE.
|
||||
*/
|
||||
|
||||
#include "plibs.h"
|
||||
#include "pssl.h"
|
||||
#include "psynclib.h"
|
||||
#include "psslcerts.h"
|
||||
#include "psettings.h"
|
||||
#include "pcache.h"
|
||||
#include "ptimer.h"
|
||||
#include "pmemlock.h"
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/err.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#define SSL_CIPHERS \
|
||||
"ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:"\
|
||||
"DHE-RSA-AES256-GCM-SHA384:ECDH-RSA-AES256-GCM-SHA384:"\
|
||||
"ECDHE-RSA-AES256-SHA384:DHE-RSA-AES256-SHA256:"\
|
||||
"AES256-GCM-SHA384:AES256-SHA256;"
|
||||
|
||||
|
||||
#if defined(PSYNC_AES_HW_MSC)
|
||||
#include <intrin.h>
|
||||
#include <wmmintrin.h>
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
SSL *ssl;
|
||||
int isbroken;
|
||||
char cachekey[];
|
||||
} ssl_connection_t;
|
||||
|
||||
static SSL_CTX *globalctx=NULL;
|
||||
static pthread_mutex_t *olocks;
|
||||
|
||||
#if defined(PSYNC_AES_HW)
|
||||
int psync_ssl_hw_aes;
|
||||
#endif
|
||||
|
||||
PSYNC_THREAD int psync_ssl_errno;
|
||||
|
||||
static void openssl_locking_callback(int mode, int type, const char *file, int line){
|
||||
if (mode&CRYPTO_LOCK)
|
||||
pthread_mutex_lock(&(olocks[type]));
|
||||
else
|
||||
pthread_mutex_unlock(&(olocks[type]));
|
||||
}
|
||||
|
||||
static void openssl_thread_id(CRYPTO_THREADID *id){
|
||||
CRYPTO_THREADID_set_pointer(id, &psync_ssl_errno);
|
||||
}
|
||||
|
||||
static int openssl_locking_default(int *num, int cnt, int type, const char *file, int line){
|
||||
openssl_locking_callback(CRYPTO_LOCK|CRYPTO_WRITE, type, file, line);
|
||||
cnt+=*num;
|
||||
*num=cnt;
|
||||
openssl_locking_callback(CRYPTO_UNLOCK|CRYPTO_WRITE, type, file, line);
|
||||
return cnt;
|
||||
}
|
||||
|
||||
static int openssl_locking_add(int *num, int cnt, int type, const char *file, int line){
|
||||
#if defined(P_OS_WINDOWS)
|
||||
if (sizeof(LONG)==sizeof(int))
|
||||
return _InterlockedAdd(num, cnt);
|
||||
else
|
||||
return openssl_locking_default(num, cnt, type, file, line);
|
||||
#elif defined(__GNUC__)
|
||||
if (1)
|
||||
return __sync_add_and_fetch(num, cnt);
|
||||
else
|
||||
return openssl_locking_default(num, cnt, type, file, line);
|
||||
#else
|
||||
return openssl_locking_default(num, cnt, type, file, line);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void openssl_thread_setup(){
|
||||
int i, n;
|
||||
n=CRYPTO_num_locks();
|
||||
olocks=psync_new_cnt(pthread_mutex_t, n);
|
||||
for (i=0; i<n; i++)
|
||||
pthread_mutex_init(&olocks[i], NULL);
|
||||
CRYPTO_THREADID_set_callback(openssl_thread_id);
|
||||
CRYPTO_set_locking_callback(openssl_locking_callback);
|
||||
CRYPTO_set_add_lock_callback(openssl_locking_add);
|
||||
}
|
||||
|
||||
#if defined(PSYNC_AES_HW_GCC)
|
||||
static int psync_ssl_detect_aes_hw(){
|
||||
uint32_t eax, ecx;
|
||||
eax=1;
|
||||
__asm__("cpuid"
|
||||
: "=c"(ecx)
|
||||
: "a"(eax)
|
||||
: "%ebx", "%edx");
|
||||
ecx=(ecx>>25)&1;
|
||||
if (ecx)
|
||||
debug(D_NOTICE, "hardware AES support detected");
|
||||
else
|
||||
debug(D_NOTICE, "hardware AES support not detected");
|
||||
return ecx;
|
||||
}
|
||||
#elif defined(PSYNC_AES_HW_MSC)
|
||||
static int psync_ssl_detect_aes_hw(){
|
||||
int info[4];
|
||||
int ret;
|
||||
__cpuid(info, 1);
|
||||
ret=(info[2]>>25)&1;
|
||||
if (ret)
|
||||
debug(D_NOTICE, "hardware AES support detected");
|
||||
else
|
||||
debug(D_NOTICE, "hardware AES support not detected");
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
int psync_ssl_init(){
|
||||
BIO *bio;
|
||||
X509 *cert;
|
||||
psync_uint_t i;
|
||||
unsigned char seed[PSYNC_LHASH_DIGEST_LEN];
|
||||
#if defined(PSYNC_AES_HW)
|
||||
psync_ssl_hw_aes=psync_ssl_detect_aes_hw();
|
||||
#else
|
||||
debug(D_NOTICE, "hardware AES is not supported for this compiler");
|
||||
#endif
|
||||
if (!CRYPTO_set_locked_mem_functions(psync_locked_malloc, psync_locked_free))
|
||||
debug(D_WARNING, "failed to set locked functions for OpenSSL");
|
||||
SSL_library_init();
|
||||
OpenSSL_add_all_algorithms();
|
||||
OpenSSL_add_all_ciphers();
|
||||
SSL_load_error_strings();
|
||||
openssl_thread_setup();
|
||||
globalctx=SSL_CTX_new(TLSv1_2_client_method());
|
||||
if (likely_log(globalctx)){
|
||||
if (unlikely_log(SSL_CTX_set_cipher_list(globalctx, SSL_CIPHERS)!=1)){
|
||||
SSL_CTX_free(globalctx);
|
||||
globalctx=NULL;
|
||||
return -1;
|
||||
}
|
||||
SSL_CTX_set_verify(globalctx, SSL_VERIFY_NONE, NULL);
|
||||
SSL_CTX_set_read_ahead(globalctx, 0); // readahed breaks SSL_Pending
|
||||
SSL_CTX_set_session_cache_mode(globalctx, SSL_SESS_CACHE_CLIENT|SSL_SESS_CACHE_NO_INTERNAL);
|
||||
SSL_CTX_set_options(globalctx, SSL_OP_NO_COMPRESSION);
|
||||
SSL_CTX_set_mode(globalctx, SSL_MODE_RELEASE_BUFFERS);
|
||||
SSL_CTX_set_mode(globalctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
|
||||
for (i=0; i<ARRAY_SIZE(psync_ssl_trusted_certs); i++){
|
||||
bio=BIO_new(BIO_s_mem());
|
||||
BIO_puts(bio, psync_ssl_trusted_certs[i]);
|
||||
cert=PEM_read_bio_X509(bio, NULL, NULL, NULL);
|
||||
BIO_free(bio);
|
||||
if (likely_log(cert!=NULL)){
|
||||
X509_STORE_add_cert(SSL_CTX_get_cert_store(globalctx), cert);
|
||||
X509_free(cert);
|
||||
}
|
||||
}
|
||||
do {
|
||||
psync_get_random_seed(seed, NULL, 0, 0);
|
||||
RAND_seed(seed, PSYNC_LHASH_DIGEST_LEN);
|
||||
} while (!RAND_status());
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
void psync_ssl_memclean(void *ptr, size_t len){
|
||||
OPENSSL_cleanse(ptr, len);
|
||||
}
|
||||
|
||||
static void psync_set_ssl_error(ssl_connection_t *conn, int err){
|
||||
if (err==SSL_ERROR_WANT_READ)
|
||||
psync_ssl_errno=PSYNC_SSL_ERR_WANT_READ;
|
||||
else if (err==SSL_ERROR_WANT_WRITE)
|
||||
psync_ssl_errno=PSYNC_SSL_ERR_WANT_WRITE;
|
||||
else{
|
||||
psync_ssl_errno=PSYNC_SSL_ERR_UNKNOWN;
|
||||
conn->isbroken=1;
|
||||
debug(D_NOTICE, "got error %d from OpenSSL: %s", err, ERR_error_string(err, NULL));
|
||||
}
|
||||
}
|
||||
|
||||
// Returns non-zero when CN and hostname match.
|
||||
// Does case sensititive comparison, fine for now. Replace memcmp with str(n)casecmp if case insensitivity is needed
|
||||
static int psync_ssl_compare_cn_hostname(const char *cn, size_t cnlen, const char *hostname, size_t hostnamelen){
|
||||
if (cn[0]=='*' && cn[1]=='.') // assumes valid null terminated string
|
||||
return cnlen<=hostnamelen &&
|
||||
!memcmp(cn+1, hostname+hostnamelen-cnlen+1, cnlen) && //this will also compare the null byte
|
||||
!memchr(hostname, '.', hostnamelen-cnlen+1);
|
||||
else
|
||||
return cnlen==hostnamelen && !memcmp(cn, hostname, cnlen);
|
||||
}
|
||||
|
||||
static int psync_ssl_cn_match_hostname(X509 *cert, const char *hostname){
|
||||
X509_NAME *sname;
|
||||
X509_NAME_ENTRY *cnentry;
|
||||
ASN1_STRING *cnasn;
|
||||
const char *cnstr;
|
||||
size_t cnstrlen;
|
||||
int idx;
|
||||
sname=X509_get_subject_name(cert);
|
||||
if (unlikely_log(!sname))
|
||||
return -1;
|
||||
idx=X509_NAME_get_index_by_NID(sname, NID_commonName, -1);
|
||||
if (unlikely_log(idx<0))
|
||||
return -1;
|
||||
cnentry=X509_NAME_get_entry(sname, idx);
|
||||
if (unlikely_log(!cnentry))
|
||||
return -1;
|
||||
cnasn=X509_NAME_ENTRY_get_data(cnentry);
|
||||
if (unlikely_log(!cnasn))
|
||||
return -1;
|
||||
cnstr=(const char *)ASN1_STRING_data(cnasn);
|
||||
if (unlikely_log(!cnstr))
|
||||
return -1;
|
||||
cnstrlen=strlen(cnstr);
|
||||
if (unlikely_log(ASN1_STRING_length(cnasn)!=cnstrlen))
|
||||
return -1;
|
||||
debug(D_NOTICE, "got certificate with commonName: %s", cnstr);
|
||||
if (psync_ssl_compare_cn_hostname(cnstr, cnstrlen, hostname, strlen(hostname)))
|
||||
return 0;
|
||||
else{
|
||||
debug(D_WARNING, "hostname %s does not match certificate common name %s", hostname, cnstr);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int psync_ssl_verify_cert(SSL *ssl, const char *hostname){
|
||||
X509 *cert;
|
||||
int ret;
|
||||
if (unlikely_log(SSL_get_verify_result(ssl)!=X509_V_OK))
|
||||
return -1;
|
||||
cert=SSL_get_peer_certificate(ssl);
|
||||
if (unlikely_log(!cert))
|
||||
return -1;
|
||||
ret=psync_ssl_cn_match_hostname(cert, hostname);
|
||||
X509_free(cert);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssl_connection_t *psync_ssl_alloc_conn(SSL *ssl, const char *hostname){
|
||||
ssl_connection_t *conn;
|
||||
size_t len;
|
||||
len=strlen(hostname)+1;
|
||||
conn=(ssl_connection_t *)psync_malloc(offsetof(ssl_connection_t, cachekey)+len+4);
|
||||
conn->ssl=ssl;
|
||||
conn->isbroken=0;
|
||||
memcpy(conn->cachekey, "SSLS", 4);
|
||||
memcpy(conn->cachekey+4, hostname, len);
|
||||
return conn;
|
||||
}
|
||||
|
||||
int psync_ssl_connect(psync_socket_t sock, void **sslconn, const char *hostname){
|
||||
ssl_connection_t *conn;
|
||||
SSL *ssl;
|
||||
SSL_SESSION *sess;
|
||||
int res, err;
|
||||
ssl=SSL_new(globalctx);
|
||||
if (!ssl)
|
||||
return PRINT_RETURN_CONST(PSYNC_SSL_FAIL);
|
||||
SSL_set_fd(ssl, sock);
|
||||
conn=psync_ssl_alloc_conn(ssl, hostname);
|
||||
if ((sess=(SSL_SESSION *)psync_cache_get(conn->cachekey))){
|
||||
debug(D_NOTICE, "reusing cached session for %s", hostname);
|
||||
SSL_set_session(ssl, sess);
|
||||
SSL_SESSION_free(sess);
|
||||
}
|
||||
res=SSL_connect(ssl);
|
||||
if (res==1){
|
||||
if (unlikely(psync_ssl_verify_cert(ssl, hostname)))
|
||||
goto fail;
|
||||
*sslconn=conn;
|
||||
if (IS_DEBUG && SSL_session_reused(ssl))
|
||||
debug(D_NOTICE, "successfully reused session");
|
||||
return PSYNC_SSL_SUCCESS;
|
||||
}
|
||||
err=SSL_get_error(ssl, res);
|
||||
psync_set_ssl_error(conn, err);
|
||||
if (likely_log(err==SSL_ERROR_WANT_READ || err==SSL_ERROR_WANT_WRITE)){
|
||||
*sslconn=conn;
|
||||
return PSYNC_SSL_NEED_FINISH;
|
||||
}
|
||||
fail:
|
||||
SSL_free(ssl);
|
||||
psync_free(conn);
|
||||
return PRINT_RETURN_CONST(PSYNC_SSL_FAIL);
|
||||
}
|
||||
|
||||
int psync_ssl_connect_finish(void *sslconn, const char *hostname){
|
||||
ssl_connection_t *conn;
|
||||
int res, err;
|
||||
conn=(ssl_connection_t *)sslconn;
|
||||
res=SSL_connect(conn->ssl);
|
||||
if (res==1){
|
||||
if (unlikely(psync_ssl_verify_cert(conn->ssl, hostname)))
|
||||
goto fail;
|
||||
if (IS_DEBUG && SSL_session_reused(conn->ssl))
|
||||
debug(D_NOTICE, "successfully reused session");
|
||||
return PSYNC_SSL_SUCCESS;
|
||||
}
|
||||
err=SSL_get_error(conn->ssl, res);
|
||||
psync_set_ssl_error(conn, err);
|
||||
if (likely_log(err==SSL_ERROR_WANT_READ || err==SSL_ERROR_WANT_WRITE))
|
||||
return PSYNC_SSL_NEED_FINISH;
|
||||
fail:
|
||||
SSL_free(conn->ssl);
|
||||
psync_free(conn);
|
||||
return PRINT_RETURN_CONST(PSYNC_SSL_FAIL);
|
||||
}
|
||||
|
||||
static void psync_ssl_free_session(void *ptr){
|
||||
SSL_SESSION_free((SSL_SESSION *)ptr);
|
||||
}
|
||||
|
||||
int psync_ssl_shutdown(void *sslconn){
|
||||
ssl_connection_t *conn;
|
||||
SSL_SESSION *sess;
|
||||
int res, err;
|
||||
conn=(ssl_connection_t *)sslconn;
|
||||
sess=SSL_get1_session(conn->ssl);
|
||||
if (sess)
|
||||
psync_cache_add(conn->cachekey, sess, PSYNC_SSL_SESSION_CACHE_TIMEOUT, psync_ssl_free_session, PSYNC_MAX_SSL_SESSIONS_PER_DOMAIN);
|
||||
if (conn->isbroken)
|
||||
goto noshutdown;
|
||||
res=SSL_shutdown(conn->ssl);
|
||||
if (res!=-1)
|
||||
goto noshutdown;
|
||||
err=SSL_get_error(conn->ssl, res);
|
||||
psync_set_ssl_error(conn, err);
|
||||
if (likely_log(err==SSL_ERROR_WANT_READ || err==SSL_ERROR_WANT_WRITE))
|
||||
return PSYNC_SSL_NEED_FINISH;
|
||||
noshutdown:
|
||||
SSL_free(conn->ssl);
|
||||
psync_free(conn);
|
||||
return PSYNC_SSL_SUCCESS;
|
||||
}
|
||||
|
||||
void psync_ssl_free(void *sslconn){
|
||||
ssl_connection_t *conn;
|
||||
conn=(ssl_connection_t *)sslconn;
|
||||
SSL_free(conn->ssl);
|
||||
psync_free(conn);
|
||||
}
|
||||
|
||||
int psync_ssl_pendingdata(void *sslconn){
|
||||
return SSL_pending(((ssl_connection_t *)sslconn)->ssl);
|
||||
}
|
||||
|
||||
int psync_ssl_read(void *sslconn, void *buf, int num){
|
||||
ssl_connection_t *conn;
|
||||
int res, err;
|
||||
conn=(ssl_connection_t *)sslconn;
|
||||
res=SSL_read(conn->ssl, buf, num);
|
||||
if (res>=0)
|
||||
return res;
|
||||
err=SSL_get_error(conn->ssl, res);
|
||||
psync_set_ssl_error(conn, err);
|
||||
return PSYNC_SSL_FAIL;
|
||||
}
|
||||
|
||||
int psync_ssl_write(void *sslconn, const void *buf, int num){
|
||||
ssl_connection_t *conn;
|
||||
int res, err;
|
||||
conn=(ssl_connection_t *)sslconn;
|
||||
res=SSL_write(conn->ssl, buf, num);
|
||||
if (res>=0)
|
||||
return res;
|
||||
err=SSL_get_error(conn->ssl, res);
|
||||
psync_set_ssl_error(conn, err);
|
||||
return PSYNC_SSL_FAIL;
|
||||
}
|
||||
|
||||
void psync_ssl_rand_strong(unsigned char *buf, int num){
|
||||
static int seeds=0;
|
||||
int ret;
|
||||
if (seeds<2){
|
||||
unsigned char seed[PSYNC_LHASH_DIGEST_LEN];
|
||||
psync_get_random_seed(seed, buf, num, 1);
|
||||
RAND_seed(seed, PSYNC_LHASH_DIGEST_LEN);
|
||||
seeds++;
|
||||
}
|
||||
ret=RAND_bytes(buf, num);
|
||||
if (unlikely(ret==0)){
|
||||
unsigned char seed[PSYNC_LHASH_DIGEST_LEN];
|
||||
psync_uint_t cnt;
|
||||
cnt=0;
|
||||
while (ret==0 && cnt++<20){
|
||||
psync_get_random_seed(seed, NULL, 0, 0);
|
||||
RAND_seed(seed, PSYNC_LHASH_DIGEST_LEN);
|
||||
ret=RAND_bytes(buf, num);
|
||||
}
|
||||
}
|
||||
if (unlikely(ret!=1)){
|
||||
debug(D_CRITICAL, "could not generate %d random bytes, error %s, exiting", num, ERR_error_string(ERR_get_error(), NULL));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void psync_ssl_rand_weak(unsigned char *buf, int num){
|
||||
int ret;
|
||||
ret=RAND_pseudo_bytes(buf, num);
|
||||
if (unlikely(ret==-1)){
|
||||
debug(D_CRITICAL, "could not generate %d weak random bytes, error %s, exiting", num, ERR_error_string(ERR_get_error(), NULL));
|
||||
exit(1);
|
||||
}
|
||||
else if (unlikely(ret==0))
|
||||
debug(D_WARNING, "RAND_pseudo_bytes returned weak numbers");
|
||||
}
|
||||
|
||||
/* this function comes from OpenSSL's crypto/rsa/rsa_lib.c, this version is not (that) buggy and reformatted */
|
||||
static int RSA_memory_lock_fixed(RSA *r){
|
||||
int i, j, k, off;
|
||||
char *p;
|
||||
BIGNUM *bn, **t[6], *b;
|
||||
BN_ULONG *ul;
|
||||
if (r->d==NULL)
|
||||
return 1;
|
||||
t[0]=&r->d;
|
||||
t[1]=&r->p;
|
||||
t[2]=&r->q;
|
||||
t[3]=&r->dmp1;
|
||||
t[4]=&r->dmq1;
|
||||
t[5]=&r->iqmp;
|
||||
k=sizeof(BIGNUM)*6;
|
||||
off=k/sizeof(BN_ULONG)+1;
|
||||
j=1;
|
||||
for (i=0; i<6; i++)
|
||||
j+=(*t[i])->top;
|
||||
if ((p=OPENSSL_malloc_locked((off+j)*sizeof(BN_ULONG)))==NULL){
|
||||
RSAerr(RSA_F_RSA_MEMORY_LOCK, ERR_R_MALLOC_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
bn=(BIGNUM *)p;
|
||||
ul=(BN_ULONG *)&p[k];
|
||||
for (i=0; i<6; i++){
|
||||
b= *(t[i]);
|
||||
*(t[i])= &(bn[i]);
|
||||
memcpy((char *)&(bn[i]), (char *)b, sizeof(BIGNUM));
|
||||
bn[i].flags=BN_FLG_STATIC_DATA;
|
||||
bn[i].d=ul;
|
||||
memcpy((char *)ul, b->d, sizeof(BN_ULONG)*b->top);
|
||||
ul+=b->top;
|
||||
BN_clear_free(b);
|
||||
}
|
||||
r->flags&=~(RSA_FLAG_CACHE_PRIVATE|RSA_FLAG_CACHE_PUBLIC);
|
||||
r->bignum_data=p;
|
||||
return 1;
|
||||
}
|
||||
|
||||
psync_rsa_t psync_ssl_gen_rsa(int bits){
|
||||
RSA *rsa;
|
||||
BIGNUM *bn;
|
||||
unsigned char seed[PSYNC_LHASH_DIGEST_LEN];
|
||||
psync_get_random_seed(seed, seed, sizeof(seed), 0);
|
||||
RAND_seed(seed, PSYNC_LHASH_DIGEST_LEN);
|
||||
rsa=RSA_new();
|
||||
if (unlikely_log(!rsa))
|
||||
goto err0;
|
||||
bn=BN_new();
|
||||
if (unlikely_log(!bn))
|
||||
goto err1;
|
||||
if (unlikely_log(!BN_set_word(bn, RSA_F4)))
|
||||
goto err2;
|
||||
if (unlikely_log(!RSA_generate_key_ex(rsa, bits, bn, NULL)))
|
||||
goto err2;
|
||||
RSA_memory_lock_fixed(rsa);
|
||||
BN_free(bn);
|
||||
return rsa;
|
||||
err2:
|
||||
BN_free(bn);
|
||||
err1:
|
||||
RSA_free(rsa);
|
||||
err0:
|
||||
return PSYNC_INVALID_RSA;
|
||||
}
|
||||
|
||||
static void psync_ssl_lock_rsa(RSA *rsa){
|
||||
RSA_memory_lock_fixed(rsa);
|
||||
}
|
||||
|
||||
void psync_ssl_free_rsa(psync_rsa_t rsa){
|
||||
RSA_free(rsa);
|
||||
}
|
||||
|
||||
psync_rsa_publickey_t psync_ssl_rsa_get_public(psync_rsa_t rsa){
|
||||
return RSAPublicKey_dup(rsa);
|
||||
}
|
||||
|
||||
void psync_ssl_rsa_free_public(psync_rsa_publickey_t key){
|
||||
RSA_free(key);
|
||||
}
|
||||
|
||||
psync_rsa_privatekey_t psync_ssl_rsa_get_private(psync_rsa_t rsa){
|
||||
RSA *rsap=RSAPrivateKey_dup(rsa);
|
||||
if (rsap)
|
||||
psync_ssl_lock_rsa(rsap);
|
||||
return rsap;
|
||||
}
|
||||
|
||||
void psync_ssl_rsa_free_private(psync_rsa_privatekey_t key){
|
||||
RSA_free(key);
|
||||
}
|
||||
|
||||
psync_binary_rsa_key_t psync_ssl_rsa_public_to_binary(psync_rsa_publickey_t rsa){
|
||||
psync_binary_rsa_key_t ret;
|
||||
unsigned char *p;
|
||||
int len;
|
||||
len=i2d_RSAPublicKey(rsa, NULL);
|
||||
if (unlikely_log(len<0))
|
||||
return PSYNC_INVALID_BIN_RSA;
|
||||
ret=psync_locked_malloc(offsetof(psync_encrypted_data_struct_t, data)+len);
|
||||
ret->datalen=len;
|
||||
p=ret->data;
|
||||
if (unlikely_log(i2d_RSAPublicKey(rsa, &p)!=len)){
|
||||
psync_locked_free(ret);
|
||||
return PSYNC_INVALID_BIN_RSA;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
psync_binary_rsa_key_t psync_ssl_rsa_private_to_binary(psync_rsa_privatekey_t rsa){
|
||||
psync_binary_rsa_key_t ret;
|
||||
unsigned char *p;
|
||||
int len;
|
||||
len=i2d_RSAPrivateKey(rsa, NULL);
|
||||
if (unlikely_log(len<0))
|
||||
return PSYNC_INVALID_BIN_RSA;
|
||||
ret=psync_locked_malloc(offsetof(psync_encrypted_data_struct_t, data)+len);
|
||||
ret->datalen=len;
|
||||
p=ret->data;
|
||||
if (unlikely_log(i2d_RSAPrivateKey(rsa, &p)!=len)){
|
||||
psync_locked_free(ret);
|
||||
return PSYNC_INVALID_BIN_RSA;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
psync_rsa_publickey_t psync_ssl_rsa_load_public(const unsigned char *keydata, size_t keylen){
|
||||
return d2i_RSAPublicKey(NULL, &keydata, keylen);
|
||||
}
|
||||
|
||||
psync_rsa_privatekey_t psync_ssl_rsa_load_private(const unsigned char *keydata, size_t keylen){
|
||||
RSA *rsa=d2i_RSAPrivateKey(NULL, &keydata, keylen);
|
||||
if (rsa)
|
||||
psync_ssl_lock_rsa(rsa);
|
||||
return rsa;
|
||||
}
|
||||
|
||||
psync_rsa_publickey_t psync_ssl_rsa_binary_to_public(psync_binary_rsa_key_t bin){
|
||||
return psync_ssl_rsa_load_public(bin->data, bin->datalen);
|
||||
}
|
||||
|
||||
psync_rsa_privatekey_t psync_ssl_rsa_binary_to_private(psync_binary_rsa_key_t bin){
|
||||
return psync_ssl_rsa_load_private(bin->data, bin->datalen);
|
||||
}
|
||||
|
||||
psync_symmetric_key_t psync_ssl_gen_symmetric_key_from_pass(const char *password, size_t keylen, const unsigned char *salt, size_t saltlen, size_t iterations){
|
||||
psync_symmetric_key_t key=(psync_symmetric_key_t)psync_locked_malloc(keylen+offsetof(psync_symmetric_key_struct_t, key));
|
||||
key->keylen=keylen;
|
||||
PKCS5_PBKDF2_HMAC(password, strlen(password), salt,
|
||||
saltlen, iterations, EVP_sha512(), keylen, key->key);
|
||||
return key;
|
||||
}
|
||||
|
||||
psync_encrypted_symmetric_key_t psync_ssl_rsa_encrypt_data(psync_rsa_publickey_t rsa, const unsigned char *data, size_t datalen){
|
||||
psync_encrypted_symmetric_key_t ret;
|
||||
int len;
|
||||
ret=(psync_encrypted_symmetric_key_t)psync_malloc(offsetof(psync_encrypted_data_struct_t, data)+RSA_size(rsa));
|
||||
len=RSA_public_encrypt(datalen, data, ret->data, rsa, RSA_PKCS1_OAEP_PADDING);
|
||||
if (unlikely_log(len==-1)){
|
||||
psync_free(ret);
|
||||
return PSYNC_INVALID_ENC_SYM_KEY;
|
||||
}
|
||||
ret->datalen=len;
|
||||
return ret;
|
||||
}
|
||||
|
||||
psync_symmetric_key_t psync_ssl_rsa_decrypt_data(psync_rsa_privatekey_t rsa, const unsigned char *data, size_t datalen){
|
||||
unsigned char buff[2048];
|
||||
psync_symmetric_key_t ret;
|
||||
int len;
|
||||
len=RSA_private_decrypt(datalen, data, buff, rsa, RSA_PKCS1_OAEP_PADDING);
|
||||
if (unlikely(len==-1)){
|
||||
#if IS_DEBUG
|
||||
unsigned long e;
|
||||
e=ERR_get_error();
|
||||
debug(D_WARNING, "could not decrypt key, RSA_private_decrypt returned error %lu: %s", e, ERR_error_string(e, (char *)buff));
|
||||
#endif
|
||||
return PSYNC_INVALID_SYM_KEY;
|
||||
}
|
||||
ret=(psync_symmetric_key_t)psync_locked_malloc(offsetof(psync_symmetric_key_struct_t, key)+len);
|
||||
ret->keylen=len;
|
||||
memcpy(ret->key, buff, len);
|
||||
psync_ssl_memclean(buff, len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
psync_encrypted_symmetric_key_t psync_ssl_rsa_encrypt_symmetric_key(psync_rsa_publickey_t rsa, const psync_symmetric_key_t key){
|
||||
return psync_ssl_rsa_encrypt_data(rsa, key->key, key->keylen);
|
||||
}
|
||||
|
||||
psync_symmetric_key_t psync_ssl_rsa_decrypt_symmetric_key(psync_rsa_privatekey_t rsa, const psync_encrypted_symmetric_key_t enckey){
|
||||
return psync_ssl_rsa_decrypt_data(rsa, enckey->data, enckey->datalen);
|
||||
}
|
||||
|
||||
static AES_KEY *psync_ssl_get_aligned_aes_key(){
|
||||
unsigned char *m, *a;
|
||||
m=(unsigned char *)psync_locked_malloc(PSYNC_AES256_BLOCK_SIZE+sizeof(AES_KEY));
|
||||
a=(unsigned char *)(((((uintptr_t)m)+PSYNC_AES256_BLOCK_SIZE-1)/PSYNC_AES256_BLOCK_SIZE)*PSYNC_AES256_BLOCK_SIZE);
|
||||
a[sizeof(AES_KEY)]=a-m;
|
||||
return (AES_KEY *)a;
|
||||
}
|
||||
|
||||
static void psync_ssl_free_aligned_aes_key(AES_KEY *aes){
|
||||
unsigned char *a;
|
||||
a=(unsigned char *)aes;
|
||||
a-=a[sizeof(AES_KEY)];
|
||||
psync_ssl_memclean(aes, sizeof(AES_KEY));
|
||||
psync_locked_free(a);
|
||||
}
|
||||
|
||||
psync_aes256_encoder psync_ssl_aes256_create_encoder(psync_symmetric_key_t key){
|
||||
AES_KEY *aes;
|
||||
assert(key->keylen>=PSYNC_AES256_KEY_SIZE);
|
||||
aes=psync_ssl_get_aligned_aes_key();
|
||||
AES_set_encrypt_key(key->key, 256, aes);
|
||||
return aes;
|
||||
}
|
||||
|
||||
void psync_ssl_aes256_free_encoder(psync_aes256_encoder aes){
|
||||
psync_ssl_free_aligned_aes_key(aes);
|
||||
}
|
||||
|
||||
psync_aes256_encoder psync_ssl_aes256_create_decoder(psync_symmetric_key_t key){
|
||||
AES_KEY *aes;
|
||||
assert(key->keylen>=PSYNC_AES256_KEY_SIZE);
|
||||
aes=psync_ssl_get_aligned_aes_key();
|
||||
AES_set_decrypt_key(key->key, 256, aes);
|
||||
return aes;
|
||||
}
|
||||
|
||||
void psync_ssl_aes256_free_decoder(psync_aes256_encoder aes){
|
||||
psync_ssl_free_aligned_aes_key(aes);
|
||||
}
|
||||
|
||||
#if defined(PSYNC_AES_HW_GCC)
|
||||
|
||||
#define SSE2FUNC __attribute__((__target__("sse2")))
|
||||
|
||||
#define AESDEC ".byte 0x66,0x0F,0x38,0xDE,"
|
||||
#define AESDECLAST ".byte 0x66,0x0F,0x38,0xDF,"
|
||||
#define AESENC ".byte 0x66,0x0F,0x38,0xDC,"
|
||||
#define AESENCLAST ".byte 0x66,0x0F,0x38,0xDD,"
|
||||
|
||||
#define xmm0_xmm1 "0xC8"
|
||||
#define xmm0_xmm2 "0xD0"
|
||||
#define xmm0_xmm3 "0xD8"
|
||||
#define xmm0_xmm4 "0xE0"
|
||||
#define xmm0_xmm5 "0xE8"
|
||||
#define xmm1_xmm0 "0xC1"
|
||||
#define xmm1_xmm2 "0xD1"
|
||||
#define xmm1_xmm3 "0xD9"
|
||||
#define xmm1_xmm4 "0xE1"
|
||||
#define xmm1_xmm5 "0xE9"
|
||||
|
||||
SSE2FUNC void psync_aes256_encode_block_hw(psync_aes256_encoder enc, const unsigned char *src, unsigned char *dst){
|
||||
asm("movdqa (%0), %%xmm0\n"
|
||||
"lea 16(%0), %0\n"
|
||||
"movdqa (%1), %%xmm1\n"
|
||||
"dec %3\n"
|
||||
"pxor %%xmm0, %%xmm1\n"
|
||||
"movdqa (%0), %%xmm0\n"
|
||||
"1:\n"
|
||||
"lea 16(%0), %0\n"
|
||||
"dec %3\n"
|
||||
AESENC xmm0_xmm1 "\n"
|
||||
"movdqa (%0), %%xmm0\n"
|
||||
"jnz 1b\n"
|
||||
AESENCLAST xmm0_xmm1 "\n"
|
||||
"movdqa %%xmm1, (%2)\n"
|
||||
:
|
||||
: "r" (enc->rd_key), "r" (src), "r" (dst), "r" (enc->rounds)
|
||||
: "memory", "cc", "xmm0", "xmm1"
|
||||
);
|
||||
}
|
||||
|
||||
SSE2FUNC void psync_aes256_decode_block_hw(psync_aes256_decoder enc, const unsigned char *src, unsigned char *dst){
|
||||
asm("movdqa (%0), %%xmm0\n"
|
||||
"lea 16(%0), %0\n"
|
||||
"movdqa (%1), %%xmm1\n"
|
||||
"dec %3\n"
|
||||
"pxor %%xmm0, %%xmm1\n"
|
||||
"movdqa (%0), %%xmm0\n"
|
||||
"1:\n"
|
||||
"lea 16(%0), %0\n"
|
||||
"dec %3\n"
|
||||
AESDEC xmm0_xmm1 "\n"
|
||||
"movdqa (%0), %%xmm0\n"
|
||||
"jnz 1b\n"
|
||||
AESDECLAST xmm0_xmm1 "\n"
|
||||
"movdqa %%xmm1, (%2)\n"
|
||||
:
|
||||
: "r" (enc->rd_key), "r" (src), "r" (dst), "r" (enc->rounds)
|
||||
: "memory", "cc", "xmm0", "xmm1"
|
||||
);
|
||||
}
|
||||
|
||||
SSE2FUNC void psync_aes256_encode_2blocks_consec_hw(psync_aes256_encoder enc, const unsigned char *src, unsigned char *dst){
|
||||
asm("movdqa (%0), %%xmm0\n"
|
||||
"movdqa (%1), %%xmm1\n"
|
||||
"dec %3\n"
|
||||
"movdqa 16(%1), %%xmm2\n"
|
||||
"lea 16(%0), %0\n"
|
||||
"xorps %%xmm0, %%xmm1\n"
|
||||
"pxor %%xmm0, %%xmm2\n"
|
||||
"movdqa (%0), %%xmm0\n"
|
||||
"1:\n"
|
||||
"lea 16(%0), %0\n"
|
||||
AESENC xmm0_xmm1 "\n"
|
||||
"dec %3\n"
|
||||
AESENC xmm0_xmm2 "\n"
|
||||
"movdqa (%0), %%xmm0\n"
|
||||
"jnz 1b\n"
|
||||
AESENCLAST xmm0_xmm1 "\n"
|
||||
AESENCLAST xmm0_xmm2 "\n"
|
||||
"movdqa %%xmm1, (%2)\n"
|
||||
"movdqa %%xmm2, 16(%2)\n"
|
||||
:
|
||||
: "r" (enc->rd_key), "r" (src), "r" (dst), "r" (enc->rounds)
|
||||
: "memory", "cc", "xmm0", "xmm1", "xmm2"
|
||||
);
|
||||
}
|
||||
|
||||
SSE2FUNC void psync_aes256_decode_2blocks_consec_hw(psync_aes256_decoder enc, const unsigned char *src, unsigned char *dst){
|
||||
asm("movdqa (%0), %%xmm0\n"
|
||||
"movdqa (%1), %%xmm1\n"
|
||||
"dec %3\n"
|
||||
"movdqa 16(%1), %%xmm2\n"
|
||||
"lea 16(%0), %0\n"
|
||||
"xorps %%xmm0, %%xmm1\n"
|
||||
"pxor %%xmm0, %%xmm2\n"
|
||||
"movdqa (%0), %%xmm0\n"
|
||||
"1:\n"
|
||||
"lea 16(%0), %0\n"
|
||||
AESDEC xmm0_xmm1 "\n"
|
||||
"dec %3\n"
|
||||
AESDEC xmm0_xmm2 "\n"
|
||||
"movdqa (%0), %%xmm0\n"
|
||||
"jnz 1b\n"
|
||||
AESDECLAST xmm0_xmm1 "\n"
|
||||
AESDECLAST xmm0_xmm2 "\n"
|
||||
"movdqa %%xmm1, (%2)\n"
|
||||
"movdqa %%xmm2, 16(%2)\n"
|
||||
:
|
||||
: "r" (enc->rd_key), "r" (src), "r" (dst), "r" (enc->rounds)
|
||||
: "memory", "cc", "xmm0", "xmm1", "xmm2"
|
||||
);
|
||||
}
|
||||
|
||||
SSE2FUNC void psync_aes256_decode_4blocks_consec_xor_hw(psync_aes256_decoder enc, const unsigned char *src, unsigned char *dst, unsigned char *bxor){
|
||||
asm("movdqa (%0), %%xmm0\n"
|
||||
"shr %4\n"
|
||||
"movdqa (%1), %%xmm2\n"
|
||||
"dec %4\n"
|
||||
"movdqa 16(%1), %%xmm3\n"
|
||||
"xorps %%xmm0, %%xmm2\n"
|
||||
"movdqa 32(%1), %%xmm4\n"
|
||||
"xorps %%xmm0, %%xmm3\n"
|
||||
"movdqa 48(%1), %%xmm5\n"
|
||||
"pxor %%xmm0, %%xmm4\n"
|
||||
"movdqa 16(%0), %%xmm1\n"
|
||||
"pxor %%xmm0, %%xmm5\n"
|
||||
"1:\n"
|
||||
"lea 32(%0), %0\n"
|
||||
"dec %4\n"
|
||||
AESDEC xmm1_xmm2 "\n"
|
||||
"movdqa (%0), %%xmm0\n"
|
||||
AESDEC xmm1_xmm3 "\n"
|
||||
AESDEC xmm1_xmm4 "\n"
|
||||
AESDEC xmm1_xmm5 "\n"
|
||||
AESDEC xmm0_xmm2 "\n"
|
||||
"movdqa 16(%0), %%xmm1\n"
|
||||
AESDEC xmm0_xmm3 "\n"
|
||||
AESDEC xmm0_xmm4 "\n"
|
||||
AESDEC xmm0_xmm5 "\n"
|
||||
"jnz 1b\n"
|
||||
AESDEC xmm1_xmm2 "\n"
|
||||
"movdqa 32(%0), %%xmm0\n"
|
||||
AESDEC xmm1_xmm3 "\n"
|
||||
AESDEC xmm1_xmm4 "\n"
|
||||
AESDEC xmm1_xmm5 "\n"
|
||||
AESDECLAST xmm0_xmm2 "\n"
|
||||
AESDECLAST xmm0_xmm3 "\n"
|
||||
AESDECLAST xmm0_xmm4 "\n"
|
||||
"pxor (%3), %%xmm2\n"
|
||||
AESDECLAST xmm0_xmm5 "\n"
|
||||
"pxor 16(%3), %%xmm3\n"
|
||||
"movdqa %%xmm2, (%2)\n"
|
||||
"pxor 32(%3), %%xmm4\n"
|
||||
"movdqa %%xmm3, 16(%2)\n"
|
||||
"pxor 48(%3), %%xmm5\n"
|
||||
"movdqa %%xmm4, 32(%2)\n"
|
||||
"movdqa %%xmm5, 48(%2)\n"
|
||||
:
|
||||
: "r" (enc->rd_key), "r" (src), "r" (dst), "r" (bxor), "r" (enc->rounds)
|
||||
: "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
|
||||
);
|
||||
}
|
||||
|
||||
#elif defined(PSYNC_AES_HW_MSC)
|
||||
|
||||
void psync_aes256_encode_block_hw(psync_aes256_encoder enc, const unsigned char *src, unsigned char *dst){
|
||||
__m128i r0, r1;
|
||||
unsigned char *key;
|
||||
unsigned cnt;
|
||||
key=(unsigned char *)enc->rd_key;
|
||||
r0=_mm_load_si128((__m128i *)key);
|
||||
r1=_mm_load_si128((__m128i *)src);
|
||||
cnt=enc->rounds-1;
|
||||
key+=16;
|
||||
r1=_mm_xor_si128(r0, r1);
|
||||
r0=_mm_load_si128((__m128i *)key);
|
||||
do{
|
||||
key+=16;
|
||||
r1=_mm_aesenc_si128(r1, r0);
|
||||
r0=_mm_load_si128((__m128i *)key);
|
||||
} while (--cnt);
|
||||
r1=_mm_aesenclast_si128(r1, r0);
|
||||
_mm_store_si128((__m128i *)dst, r1);
|
||||
}
|
||||
|
||||
void psync_aes256_decode_block_hw(psync_aes256_encoder enc, const unsigned char *src, unsigned char *dst){
|
||||
__m128i r0, r1;
|
||||
unsigned char *key;
|
||||
unsigned cnt;
|
||||
key=(unsigned char *)enc->rd_key;
|
||||
r0=_mm_load_si128((__m128i *)key);
|
||||
r1=_mm_load_si128((__m128i *)src);
|
||||
cnt=enc->rounds-1;
|
||||
key+=16;
|
||||
r1=_mm_xor_si128(r0, r1);
|
||||
r0=_mm_load_si128((__m128i *)key);
|
||||
do{
|
||||
key+=16;
|
||||
r1=_mm_aesdec_si128(r1, r0);
|
||||
r0=_mm_load_si128((__m128i *)key);
|
||||
} while (--cnt);
|
||||
r1=_mm_aesdeclast_si128(r1, r0);
|
||||
_mm_store_si128((__m128i *)dst, r1);
|
||||
}
|
||||
|
||||
void psync_aes256_encode_2blocks_consec_hw(psync_aes256_encoder enc, const unsigned char *src, unsigned char *dst){
|
||||
__m128i r0, r1, r2;
|
||||
unsigned char *key;
|
||||
unsigned cnt;
|
||||
key=(unsigned char *)enc->rd_key;
|
||||
r0=_mm_load_si128((__m128i *)key);
|
||||
r1=_mm_load_si128((__m128i *)src);
|
||||
r2=_mm_load_si128((__m128i *)(src+16));
|
||||
cnt=enc->rounds-1;
|
||||
key+=16;
|
||||
r1=_mm_xor_si128(r0, r1);
|
||||
r2=_mm_xor_si128(r0, r2);
|
||||
r0=_mm_load_si128((__m128i *)key);
|
||||
do{
|
||||
key+=16;
|
||||
r1=_mm_aesenc_si128(r1, r0);
|
||||
r2=_mm_aesenc_si128(r2, r0);
|
||||
r0=_mm_load_si128((__m128i *)key);
|
||||
} while (--cnt);
|
||||
r1=_mm_aesenclast_si128(r1, r0);
|
||||
r2=_mm_aesenclast_si128(r2, r0);
|
||||
_mm_store_si128((__m128i *)dst, r1);
|
||||
_mm_store_si128((__m128i *)(dst+16), r2);
|
||||
}
|
||||
|
||||
void psync_aes256_decode_2blocks_consec_hw(psync_aes256_decoder enc, const unsigned char *src, unsigned char *dst){
|
||||
__m128i r0, r1, r2;
|
||||
unsigned char *key;
|
||||
unsigned cnt;
|
||||
key=(unsigned char *)enc->rd_key;
|
||||
r0=_mm_load_si128((__m128i *)key);
|
||||
r1=_mm_load_si128((__m128i *)src);
|
||||
r2=_mm_load_si128((__m128i *)(src+16));
|
||||
cnt=enc->rounds-1;
|
||||
key+=16;
|
||||
r1=_mm_xor_si128(r0, r1);
|
||||
r2=_mm_xor_si128(r0, r2);
|
||||
r0=_mm_load_si128((__m128i *)key);
|
||||
do{
|
||||
key+=16;
|
||||
r1=_mm_aesdec_si128(r1, r0);
|
||||
r2=_mm_aesdec_si128(r2, r0);
|
||||
r0=_mm_load_si128((__m128i *)key);
|
||||
} while (--cnt);
|
||||
r1=_mm_aesdeclast_si128(r1, r0);
|
||||
r2=_mm_aesdeclast_si128(r2, r0);
|
||||
_mm_store_si128((__m128i *)dst, r1);
|
||||
_mm_store_si128((__m128i *)(dst+16), r2);
|
||||
}
|
||||
|
||||
void psync_aes256_decode_4blocks_consec_xor_hw(psync_aes256_decoder enc, const unsigned char *src, unsigned char *dst, unsigned char *bxor){
|
||||
__m128i r0, r1, r2, r3, r4;
|
||||
unsigned char *key;
|
||||
unsigned cnt;
|
||||
key=(unsigned char *)enc->rd_key;
|
||||
r0=_mm_load_si128((__m128i *)key);
|
||||
r1=_mm_load_si128((__m128i *)src);
|
||||
r2=_mm_load_si128((__m128i *)(src+16));
|
||||
r3=_mm_load_si128((__m128i *)(src+32));
|
||||
r4=_mm_load_si128((__m128i *)(src+48));
|
||||
cnt=enc->rounds-1;
|
||||
key+=16;
|
||||
r1=_mm_xor_si128(r0, r1);
|
||||
r2=_mm_xor_si128(r0, r2);
|
||||
r3=_mm_xor_si128(r0, r3);
|
||||
r4=_mm_xor_si128(r0, r4);
|
||||
r0=_mm_load_si128((__m128i *)key);
|
||||
do{
|
||||
key+=16;
|
||||
r1=_mm_aesdec_si128(r1, r0);
|
||||
r2=_mm_aesdec_si128(r2, r0);
|
||||
r3=_mm_aesdec_si128(r3, r0);
|
||||
r4=_mm_aesdec_si128(r4, r0);
|
||||
r0=_mm_load_si128((__m128i *)key);
|
||||
} while (--cnt);
|
||||
r1=_mm_aesdeclast_si128(r1, r0);
|
||||
r2=_mm_aesdeclast_si128(r2, r0);
|
||||
r3=_mm_aesdeclast_si128(r3, r0);
|
||||
r4=_mm_aesdeclast_si128(r4, r0);
|
||||
r0=_mm_load_si128((__m128i *)bxor);
|
||||
r1=_mm_xor_si128(r0, r1);
|
||||
r0=_mm_load_si128((__m128i *)(bxor+16));
|
||||
_mm_store_si128((__m128i *)dst, r1);
|
||||
r2=_mm_xor_si128(r0, r2);
|
||||
r0=_mm_load_si128((__m128i *)(bxor+32));
|
||||
_mm_store_si128((__m128i *)(dst+16), r2);
|
||||
r3=_mm_xor_si128(r0, r3);
|
||||
r0=_mm_load_si128((__m128i *)(bxor+48));
|
||||
_mm_store_si128((__m128i *)(dst+32), r3);
|
||||
r4=_mm_xor_si128(r0, r4);
|
||||
_mm_store_si128((__m128i *)(dst+48), r4);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(PSYNC_AES_HW)
|
||||
|
||||
void psync_aes256_decode_4blocks_consec_xor_sw(psync_aes256_decoder enc, const unsigned char *src, unsigned char *dst, unsigned char *bxor){
|
||||
unsigned long i;
|
||||
AES_decrypt(src, dst, enc);
|
||||
AES_decrypt(src+PSYNC_AES256_BLOCK_SIZE, dst+PSYNC_AES256_BLOCK_SIZE, enc);
|
||||
AES_decrypt(src+PSYNC_AES256_BLOCK_SIZE*2, dst+PSYNC_AES256_BLOCK_SIZE*2, enc);
|
||||
AES_decrypt(src+PSYNC_AES256_BLOCK_SIZE*3, dst+PSYNC_AES256_BLOCK_SIZE*3, enc);
|
||||
for (i=0; i<PSYNC_AES256_BLOCK_SIZE*4/sizeof(unsigned long); i++)
|
||||
((unsigned long *)dst)[i]^=((unsigned long *)bxor)[i];
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,538 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2013-2014 Anton Titov.
|
||||
|
||||
Copyright (c) 2013-2014 pCloud Ltd. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met: Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer. Redistributions in binary form must reproduce the
|
||||
above copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution. Neither the name of pCloud Ltd nor the
|
||||
names of its contributors may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL pCloud
|
||||
Ltd BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGE.
|
||||
*/
|
||||
|
||||
#include "pssl.h"
|
||||
#include "psynclib.h"
|
||||
#include "plibs.h"
|
||||
#include "pcompat.h"
|
||||
#include "psettings.h"
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <CommonCrypto/CommonHMAC.h>
|
||||
#include <Security/SecureTransport.h>
|
||||
#include <Security/SecImportExport.h>
|
||||
#include <Security/Security.h>
|
||||
#include <Security/SecKey.h>
|
||||
|
||||
#define kSecPaddingOAEP 2
|
||||
|
||||
OSStatus SecKeyEncrypt(
|
||||
SecKeyRef key,
|
||||
SecPadding padding,
|
||||
const uint8_t *plainText,
|
||||
size_t plainTextLen,
|
||||
uint8_t *cipherText,
|
||||
size_t *cipherTextLen);
|
||||
|
||||
OSStatus SecKeyDecrypt(
|
||||
SecKeyRef key,
|
||||
SecPadding padding,
|
||||
const uint8_t *cipherText,
|
||||
size_t cipherTextLen,
|
||||
uint8_t *plainText,
|
||||
size_t *plainTextLen);
|
||||
|
||||
PSYNC_THREAD int psync_ssl_errno;
|
||||
|
||||
int psync_ssl_init(){
|
||||
return 0;
|
||||
}
|
||||
|
||||
void psync_ssl_memclean(void *ptr, size_t len){
|
||||
volatile unsigned char *c=(volatile unsigned char *)ptr;
|
||||
while (len--)
|
||||
*c++=0;
|
||||
}
|
||||
|
||||
static OSStatus psync_myread(SSLConnectionRef conn, void *data, size_t *len){
|
||||
psync_socket_t sock=(psync_socket_t)conn;
|
||||
size_t llen=*len;
|
||||
ssize_t rd=read(sock, data, llen);
|
||||
if (likely(rd>0)){
|
||||
*len=rd;
|
||||
if (rd==llen)
|
||||
return noErr;
|
||||
psync_ssl_errno=PSYNC_SSL_ERR_WANT_READ;
|
||||
return errSSLWouldBlock;
|
||||
}
|
||||
else if (rd==0){
|
||||
*len=0;
|
||||
return errSSLClosedNoNotify;
|
||||
}
|
||||
else {
|
||||
*len=0;
|
||||
if (errno==EAGAIN || errno==EINTR){
|
||||
psync_ssl_errno=PSYNC_SSL_ERR_WANT_READ;
|
||||
return errSSLWouldBlock;
|
||||
}
|
||||
else
|
||||
return errSSLClosedAbort;
|
||||
}
|
||||
}
|
||||
|
||||
static OSStatus psync_mywrite(SSLConnectionRef conn, const void *data, size_t *len){
|
||||
psync_socket_t sock=(psync_socket_t)conn;
|
||||
size_t llen=*len;
|
||||
ssize_t rd=write(sock, data, llen);
|
||||
if (likely(rd>=0)){
|
||||
*len=rd;
|
||||
if (rd==llen)
|
||||
return noErr;
|
||||
psync_ssl_errno=PSYNC_SSL_ERR_WANT_WRITE;
|
||||
return errSSLWouldBlock;
|
||||
}
|
||||
else {
|
||||
*len=0;
|
||||
if (errno==EAGAIN || errno==EINTR){
|
||||
psync_ssl_errno=PSYNC_SSL_ERR_WANT_WRITE;
|
||||
return errSSLWouldBlock;
|
||||
}
|
||||
else
|
||||
return errSSLClosedAbort;
|
||||
}
|
||||
}
|
||||
|
||||
int psync_ssl_connect(psync_socket_t sock, void **sslconn, const char *hostname){
|
||||
SSLContextRef ref;
|
||||
OSStatus st;
|
||||
ref=SSLCreateContext(kCFAllocatorDefault, kSSLClientSide, kSSLStreamType);
|
||||
if (unlikely_log(!ref))
|
||||
goto err1;
|
||||
if (unlikely_log(SSLSetIOFuncs(ref, psync_myread, psync_mywrite)!=noErr))
|
||||
goto err2;
|
||||
if (unlikely_log(SSLSetConnection(ref, (SSLConnectionRef)(uintptr_t)sock)!=noErr))
|
||||
goto err2;
|
||||
if (hostname && unlikely_log(SSLSetPeerDomainName(ref, hostname, strlen(hostname))!=noErr))
|
||||
goto err2;
|
||||
st=SSLHandshake(ref);
|
||||
if (st==noErr){
|
||||
*sslconn=ref;
|
||||
return PSYNC_SSL_SUCCESS;
|
||||
}
|
||||
else if (st==errSSLWouldBlock){
|
||||
*sslconn=ref;
|
||||
return PSYNC_SSL_NEED_FINISH;
|
||||
}
|
||||
debug(D_WARNING, "connection failed with status %d", (int)st);
|
||||
err2:
|
||||
CFRelease(ref);
|
||||
err1:
|
||||
psync_ssl_errno=PSYNC_SSL_ERR_UNKNOWN;
|
||||
return PSYNC_SSL_FAIL;
|
||||
}
|
||||
|
||||
int psync_ssl_connect_finish(void *sslconn, const char *hostname){
|
||||
SSLContextRef ref;
|
||||
OSStatus st;
|
||||
ref=(SSLContextRef)sslconn;
|
||||
st=SSLHandshake(ref);
|
||||
if (st==noErr)
|
||||
return PSYNC_SSL_SUCCESS;
|
||||
else if (st==errSSLWouldBlock)
|
||||
return PSYNC_SSL_NEED_FINISH;
|
||||
CFRelease(ref);
|
||||
debug(D_WARNING, "connection failed with status %d", (int)st);
|
||||
psync_ssl_errno=PSYNC_SSL_ERR_UNKNOWN;
|
||||
return PSYNC_SSL_FAIL;
|
||||
}
|
||||
|
||||
int psync_ssl_shutdown(void *sslconn){
|
||||
SSLContextRef ref;
|
||||
OSStatus st;
|
||||
ref=(SSLContextRef)sslconn;
|
||||
st=SSLClose(ref);
|
||||
if (st==errSSLWouldBlock)
|
||||
return PSYNC_SSL_NEED_FINISH;
|
||||
CFRelease(ref);
|
||||
if (st==noErr)
|
||||
return PSYNC_SSL_SUCCESS;
|
||||
psync_ssl_errno=PSYNC_SSL_ERR_UNKNOWN;
|
||||
return PSYNC_SSL_FAIL;
|
||||
}
|
||||
|
||||
void psync_ssl_free(void *sslconn){
|
||||
CFRelease((SSLContextRef)sslconn);
|
||||
}
|
||||
|
||||
int psync_ssl_pendingdata(void *sslconn){
|
||||
size_t p;
|
||||
if (SSLGetBufferedReadSize((SSLContextRef)sslconn, &p)==noErr)
|
||||
return p;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int psync_ssl_read(void *sslconn, void *buf, int num){
|
||||
size_t ret;
|
||||
OSStatus st;
|
||||
psync_ssl_errno=PSYNC_SSL_ERR_UNKNOWN;
|
||||
st=SSLRead((SSLContextRef)sslconn, buf, num, &ret);
|
||||
if (st!=noErr){
|
||||
if (st==errSSLWouldBlock && ret)
|
||||
return ret;
|
||||
else if (st==errSSLClosedGraceful)
|
||||
return 0;
|
||||
else{
|
||||
if (st!=errSSLWouldBlock)
|
||||
debug(D_WARNING, "read failed with error %d", (int)st);
|
||||
return PSYNC_SSL_FAIL;
|
||||
}
|
||||
}
|
||||
else
|
||||
return ret;
|
||||
}
|
||||
|
||||
int psync_ssl_write(void *sslconn, const void *buf, int num){
|
||||
size_t ret;
|
||||
OSStatus st;
|
||||
psync_ssl_errno=PSYNC_SSL_ERR_UNKNOWN;
|
||||
st=SSLWrite((SSLContextRef)sslconn, buf, num, &ret);
|
||||
if (st!=noErr){
|
||||
if (st==errSSLWouldBlock && ret)
|
||||
return ret;
|
||||
else{
|
||||
if (st!=errSSLWouldBlock)
|
||||
debug(D_WARNING, "write failed with error %d", (int)st);
|
||||
return PSYNC_SSL_FAIL;
|
||||
}
|
||||
}
|
||||
else
|
||||
return ret;
|
||||
}
|
||||
|
||||
void psync_ssl_rand_strong(unsigned char *buf, int num){
|
||||
ssize_t ret;
|
||||
int fd;
|
||||
fd=open("/dev/random", O_RDONLY);
|
||||
if (unlikely_log(fd==-1))
|
||||
goto err;
|
||||
while (num){
|
||||
ret=read(fd, buf, num);
|
||||
if (unlikely_log(ret<=0))
|
||||
goto err;
|
||||
num-=ret;
|
||||
buf+=ret;
|
||||
}
|
||||
close(fd);
|
||||
return;
|
||||
err:
|
||||
debug(D_CRITICAL, "could not open /dev/random");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void psync_ssl_rand_weak(unsigned char *buf, int num){
|
||||
sqlite3_randomness(num, buf);
|
||||
}
|
||||
|
||||
psync_rsa_t psync_ssl_gen_rsa(int bits){
|
||||
psync_rsa_t ret;
|
||||
SecKeyRef public_key, private_key;
|
||||
CFDictionaryRef dict;
|
||||
CFTypeRef keys[2], values[2];
|
||||
OSStatus st;
|
||||
keys[0]=kSecAttrKeyType;
|
||||
values[0]=kSecAttrKeyTypeRSA;
|
||||
keys[1]=kSecAttrKeySizeInBits;
|
||||
values[1]=CFNumberCreate(NULL, kCFNumberIntType, &bits);
|
||||
dict=CFDictionaryCreate(NULL, keys, values, ARRAY_SIZE(keys), NULL, NULL);
|
||||
st=SecKeyGeneratePair(dict, &public_key, &private_key);
|
||||
CFRelease(dict);
|
||||
CFRelease(values[1]);
|
||||
if (unlikely(st!=errSecSuccess)){
|
||||
debug(D_ERROR, "RSA key generation failed with error %d", (int)st);
|
||||
return PSYNC_INVALID_RSA;
|
||||
}
|
||||
ret=psync_new(psync_rsa_struct_t);
|
||||
ret->public_key=public_key;
|
||||
ret->private_key=private_key;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void psync_ssl_free_rsa(psync_rsa_t rsa){
|
||||
CFRelease(rsa->public_key);
|
||||
CFRelease(rsa->private_key);
|
||||
psync_free(rsa);
|
||||
}
|
||||
|
||||
psync_rsa_publickey_t psync_ssl_rsa_get_public(psync_rsa_t rsa){
|
||||
CFRetain(rsa->public_key);
|
||||
return rsa->public_key;
|
||||
}
|
||||
|
||||
void psync_ssl_rsa_free_public(psync_rsa_publickey_t key){
|
||||
CFRelease(key);
|
||||
}
|
||||
|
||||
psync_rsa_privatekey_t psync_ssl_rsa_get_private(psync_rsa_t rsa){
|
||||
CFRetain(rsa->private_key);
|
||||
return rsa->private_key;
|
||||
}
|
||||
|
||||
void psync_ssl_rsa_free_private(psync_rsa_privatekey_t key){
|
||||
CFRelease(key);
|
||||
}
|
||||
|
||||
psync_binary_rsa_key_t psync_ssl_rsa_public_to_binary(psync_rsa_publickey_t rsa){
|
||||
psync_binary_rsa_key_t ret;
|
||||
CFDictionaryRef dict;
|
||||
CFTypeRef keys[4], values[4], arrval[1];
|
||||
CFArrayRef arr;
|
||||
OSStatus st;
|
||||
CFDataRef data;
|
||||
CFIndex len;
|
||||
arrval[0]=rsa;
|
||||
arr=CFArrayCreate(NULL, arrval, 1, NULL);
|
||||
keys[0]=kSecAttrKeyType;
|
||||
values[0]=kSecAttrKeyTypeRSA;
|
||||
keys[1]=kSecReturnData;
|
||||
values[1]=kCFBooleanTrue;
|
||||
keys[2]=kSecClass;
|
||||
values[2]=kSecClassKey;
|
||||
keys[3]=kSecMatchItemList;
|
||||
values[3]=arr;
|
||||
dict=CFDictionaryCreate(NULL, keys, values, ARRAY_SIZE(keys), NULL, NULL);
|
||||
data=NULL;
|
||||
st=SecItemCopyMatching(dict, (CFTypeRef *)&data);
|
||||
CFRelease(dict);
|
||||
CFRelease(arr);
|
||||
if (unlikely_log(st!=errSecSuccess))
|
||||
return PSYNC_INVALID_BIN_RSA;
|
||||
len=CFDataGetLength(data);
|
||||
ret=psync_malloc(offsetof(psync_encrypted_data_struct_t, data)+len);
|
||||
ret->datalen=len;
|
||||
memcpy(ret->data, CFDataGetBytePtr(data), len);
|
||||
CFRelease(data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
psync_binary_rsa_key_t psync_ssl_rsa_private_to_binary(psync_rsa_privatekey_t rsa){
|
||||
psync_binary_rsa_key_t ret;
|
||||
CFDictionaryRef dict;
|
||||
CFTypeRef keys[4], values[4], arrval[1];
|
||||
CFArrayRef arr;
|
||||
OSStatus st;
|
||||
CFDataRef data;
|
||||
CFIndex len;
|
||||
arrval[0]=rsa;
|
||||
arr=CFArrayCreate(NULL, arrval, 1, NULL);
|
||||
keys[0]=kSecAttrKeyType;
|
||||
values[0]=kSecAttrKeyTypeRSA;
|
||||
keys[1]=kSecReturnData;
|
||||
values[1]=kCFBooleanTrue;
|
||||
keys[2]=kSecClass;
|
||||
values[2]=kSecAttrKeyClassPrivate;
|
||||
keys[3]=kSecMatchItemList;
|
||||
values[3]=arr;
|
||||
dict=CFDictionaryCreate(NULL, keys, values, ARRAY_SIZE(keys), NULL, NULL);
|
||||
data=NULL;
|
||||
st=SecItemCopyMatching(dict, (CFTypeRef *)&data);
|
||||
CFRelease(dict);
|
||||
CFRelease(arr);
|
||||
if (unlikely_log(st!=errSecSuccess))
|
||||
return PSYNC_INVALID_BIN_RSA;
|
||||
len=CFDataGetLength(data);
|
||||
ret=psync_malloc(offsetof(psync_encrypted_data_struct_t, data)+len);
|
||||
ret->datalen=len;
|
||||
memcpy(ret->data, CFDataGetBytePtr(data), len);
|
||||
CFRelease(data);
|
||||
return ret;
|
||||
}
|
||||
psync_rsa_publickey_t psync_ssl_rsa_binary_to_public(psync_binary_rsa_key_t bin){
|
||||
/* on iOS SecKeyCreateRSAPublicKey can be used */
|
||||
SecKeyRef ret;
|
||||
SecExternalFormat form;
|
||||
SecExternalItemType type;
|
||||
CFDataRef data;
|
||||
CFArrayRef out;
|
||||
OSStatus st;
|
||||
|
||||
form=kSecFormatUnknown;
|
||||
type=kSecItemTypePublicKey;
|
||||
data=CFDataCreate(NULL, bin->data, bin->datalen);
|
||||
st=SecItemImport(data, NULL, &form, &type, 0, NULL, NULL, &out);
|
||||
CFRelease(data);
|
||||
if (unlikely_log(st!=errSecSuccess))
|
||||
PSYNC_INVALID_RSA;
|
||||
ret=(SecKeyRef)CFArrayGetValueAtIndex(out, 0);
|
||||
if (unlikely_log(ret==NULL)){
|
||||
CFRelease(out);
|
||||
return PSYNC_INVALID_RSA;
|
||||
}
|
||||
CFRetain(ret);
|
||||
CFRelease(out);
|
||||
return ret;
|
||||
}
|
||||
|
||||
psync_rsa_privatekey_t psync_ssl_rsa_binary_to_private(psync_binary_rsa_key_t bin){
|
||||
SecKeyRef ret;
|
||||
SecExternalFormat form;
|
||||
SecExternalItemType type;
|
||||
CFDataRef data;
|
||||
CFArrayRef out;
|
||||
OSStatus st;
|
||||
|
||||
form=kSecFormatUnknown;
|
||||
type=kSecItemTypePrivateKey;
|
||||
data=CFDataCreate(NULL, bin->data, bin->datalen);
|
||||
st=SecItemImport(data, NULL, &form, &type, 0, NULL, NULL, &out);
|
||||
CFRelease(data);
|
||||
if (unlikely_log(st!=errSecSuccess))
|
||||
PSYNC_INVALID_RSA;
|
||||
ret=(SecKeyRef)CFArrayGetValueAtIndex(out, 0);
|
||||
if (unlikely_log(ret==NULL)){
|
||||
CFRelease(out);
|
||||
return PSYNC_INVALID_RSA;
|
||||
}
|
||||
CFRetain(ret);
|
||||
CFRelease(out);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void PKCS5_PBKDF2_HMAC_SHA1(const char *pass, size_t passlen, const unsigned char *salt, size_t saltlen,
|
||||
unsigned long cnt, size_t keylen, unsigned char *out){
|
||||
unsigned char sha1hmacbin[CC_SHA1_DIGEST_LENGTH], itmp[4];
|
||||
size_t clen;
|
||||
uint32_t iter, i, j;
|
||||
CCHmacContext hctx;
|
||||
iter=1;
|
||||
while (keylen){
|
||||
if (keylen>CC_SHA1_DIGEST_LENGTH)
|
||||
clen=CC_SHA1_DIGEST_LENGTH;
|
||||
else
|
||||
clen=keylen;
|
||||
itmp[0]=(unsigned char)((iter>>24)&0xff);
|
||||
itmp[1]=(unsigned char)((iter>>16)&0xff);
|
||||
itmp[2]=(unsigned char)((iter>>8)&0xff);
|
||||
itmp[3]=(unsigned char)(iter&0xff);
|
||||
CCHmacInit(&hctx, kCCHmacAlgSHA1, pass, passlen);
|
||||
CCHmacUpdate(&hctx, salt, saltlen);
|
||||
CCHmacUpdate(&hctx, itmp, 4);
|
||||
CCHmacFinal(&hctx, sha1hmacbin);
|
||||
memcpy(out, sha1hmacbin, clen);
|
||||
for (i=1; i<cnt; i++){
|
||||
CCHmac(kCCHmacAlgSHA1, pass, passlen, sha1hmacbin, CC_SHA1_DIGEST_LENGTH, sha1hmacbin);
|
||||
for(j=0; j<clen; j++)
|
||||
out[j]^=sha1hmacbin[j];
|
||||
}
|
||||
out+=clen;
|
||||
keylen-=clen;
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
|
||||
psync_symmetric_key_t psync_ssl_gen_symmetric_key_from_pass(const char *password, size_t keylen, const char *salt, size_t saltlen){
|
||||
psync_symmetric_key_t key=(psync_symmetric_key_t)psync_malloc(keylen+offsetof(psync_symmetric_key_struct_t, key));
|
||||
key->keylen=keylen;
|
||||
PKCS5_PBKDF2_HMAC_SHA1(password, strlen(password), (const unsigned char *)salt,
|
||||
saltlen, PSYNC_CRYPTO_PASS_TO_KEY_ITERATIONS, keylen, key->key);
|
||||
return key;
|
||||
/* CFDictionaryRef dict;
|
||||
CFTypeRef keys[4], values[4];
|
||||
CFStringRef pass;
|
||||
SecKeyRef ret;
|
||||
int num;
|
||||
keys[0]=kSecAttrSalt;
|
||||
values[0]=CFDataCreate(kCFAllocatorDefault, (const unsigned char *)PSYNC_CRYPTO_PASS_TO_KEY_SALT, sizeof(PSYNC_CRYPTO_PASS_TO_KEY_SALT)-1);
|
||||
keys[1]=kSecAttrPRF;
|
||||
values[1]=kSecAttrPRFHmacAlgSHA1;
|
||||
num=PSYNC_CRYPTO_PASS_TO_KEY_ITERATIONS;
|
||||
keys[2]=kSecAttrRounds;
|
||||
values[2]=CFNumberCreate(NULL, kCFNumberIntType, &num);
|
||||
num=keylen*8;
|
||||
keys[3]=kSecAttrKeySizeInBits;
|
||||
values[3]=CFNumberCreate(NULL, kCFNumberIntType, &num);
|
||||
dict=CFDictionaryCreate(NULL, keys, values, ARRAY_SIZE(keys), NULL, NULL);
|
||||
pass=CFStringCreateWithCStringNoCopy(NULL, password, kCFStringEncodingUTF8, NULL);
|
||||
ret=SecKeyDeriveFromPassword(pass, dict, NULL);
|
||||
CFRelease(pass);
|
||||
CFRelease(dict);
|
||||
CFRelease(values[0]);
|
||||
CFRelease(values[2]);
|
||||
CFRelease(values[3]);
|
||||
return ret;*/
|
||||
}
|
||||
|
||||
psync_encrypted_symmetric_key_t psync_ssl_rsa_encrypt_symmetric_key(psync_rsa_publickey_t rsa, const psync_symmetric_key_t key){
|
||||
size_t elen;
|
||||
psync_encrypted_symmetric_key_t ret;
|
||||
OSStatus st;
|
||||
elen=SecKeyGetBlockSize(rsa);
|
||||
ret=(psync_encrypted_symmetric_key_t)psync_malloc(offsetof(psync_encrypted_data_struct_t, data)+elen);
|
||||
st=SecKeyEncrypt(rsa, kSecPaddingOAEP, key->key, key->keylen, ret->data, &elen);
|
||||
if (unlikely_log(st!=errSecSuccess)){
|
||||
psync_free(ret);
|
||||
return PSYNC_INVALID_ENC_SYM_KEY;
|
||||
}
|
||||
ret->datalen=elen;
|
||||
return ret;
|
||||
}
|
||||
|
||||
psync_symmetric_key_t psync_ssl_rsa_decrypt_symmetric_key(psync_rsa_privatekey_t rsa, const psync_encrypted_symmetric_key_t enckey){
|
||||
unsigned char buff[2048];
|
||||
size_t len;
|
||||
psync_symmetric_key_t ret;
|
||||
OSStatus st;
|
||||
st=SecKeyDecrypt(rsa, kSecPaddingOAEP, enckey->data, enckey->datalen, buff, &len);
|
||||
if (unlikely_log(st!=errSecSuccess))
|
||||
return PSYNC_INVALID_SYM_KEY;
|
||||
ret=(psync_symmetric_key_t)psync_malloc(offsetof(psync_symmetric_key_struct_t, key)+len);
|
||||
ret->keylen=len;
|
||||
memcpy(ret->key, buff, len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
psync_aes256_encoder psync_ssl_aes256_create_encoder(psync_symmetric_key_t key){
|
||||
CCCryptorRef ret;
|
||||
assert(key->keylen>=PSYNC_AES256_KEY_SIZE);
|
||||
if (unlikely_log(CCCryptorCreate(kCCEncrypt, kCCAlgorithmAES128, kCCOptionECBMode, key->key, PSYNC_AES256_KEY_SIZE, NULL, &ret)!=kCCSuccess))
|
||||
return PSYNC_INVALID_ENCODER;
|
||||
else
|
||||
return ret;
|
||||
}
|
||||
|
||||
void psync_ssl_aes256_free_encoder(psync_aes256_encoder aes){
|
||||
CCCryptorRelease(aes);
|
||||
}
|
||||
|
||||
psync_aes256_encoder psync_ssl_aes256_create_decoder(psync_symmetric_key_t key){
|
||||
CCCryptorRef ret;
|
||||
assert(key->keylen>=PSYNC_AES256_KEY_SIZE);
|
||||
if (unlikely_log(CCCryptorCreate(kCCDecrypt, kCCAlgorithmAES128, kCCOptionECBMode, key->key, PSYNC_AES256_KEY_SIZE, NULL, &ret)!=kCCSuccess))
|
||||
return PSYNC_INVALID_ENCODER;
|
||||
else
|
||||
return ret;
|
||||
}
|
||||
|
||||
void psync_ssl_aes256_free_decoder(psync_aes256_encoder aes){
|
||||
CCCryptorRelease(aes);
|
||||
}
|
||||
Loading…
Reference in New Issue