themis_status_t themis_secure_message_wrap(const uint8_t* private_key, const size_t private_key_length, const uint8_t* public_key, const size_t public_key_length, const uint8_t* message, const size_t message_length, uint8_t* wrapped_message, size_t* wrapped_message_length){ THEMIS_CHECK_PARAM(private_key!=NULL); THEMIS_CHECK_PARAM(private_key_length!=0); THEMIS_CHECK_PARAM(message!=NULL); THEMIS_CHECK_PARAM(message_length!=0); THEMIS_CHECK_PARAM(wrapped_message_length!=NULL); if(public_key==NULL && public_key_length==0){ themis_secure_message_signer_t* ctx=NULL; ctx = themis_secure_message_signer_init(private_key, private_key_length); THEMIS_CHECK(ctx!=NULL); themis_status_t res=themis_secure_message_signer_proceed(ctx, message, message_length, wrapped_message, wrapped_message_length); themis_secure_message_signer_destroy(ctx); return res; } else { THEMIS_CHECK_PARAM(public_key!=NULL); THEMIS_CHECK_PARAM(public_key_length!=0); themis_secure_message_encrypter_t* ctx=NULL; ctx = themis_secure_message_encrypter_init(private_key, private_key_length, public_key, public_key_length); THEMIS_CHECK(ctx!=NULL); themis_status_t res=themis_secure_message_encrypter_proceed(ctx, message, message_length, wrapped_message, wrapped_message_length); themis_secure_message_encrypter_destroy(ctx); return res; } return THEMIS_INVALID_PARAMETER; }
themis_status_t themis_secure_message_ec_decrypter_proceed(themis_secure_message_ec_t* ctx, const uint8_t* wrapped_message, const size_t wrapped_message_length, uint8_t* message, size_t* message_length){ THEMIS_CHECK_PARAM(ctx!=NULL); THEMIS_CHECK_PARAM(wrapped_message_length>sizeof(themis_secure_encrypted_message_hdr_t)); themis_secure_encrypted_message_hdr_t* hdr=(themis_secure_encrypted_message_hdr_t*)wrapped_message; THEMIS_CHECK_PARAM(hdr->message_hdr.message_type==THEMIS_SECURE_MESSAGE_EC_ENCRYPTED && wrapped_message_length==hdr->message_hdr.message_length); size_t computed_length=0; THEMIS_CHECK(themis_secure_cell_decrypt_seal(ctx->shared_secret, ctx->shared_secret_length, NULL,0,wrapped_message+sizeof(themis_secure_encrypted_message_hdr_t), wrapped_message_length-sizeof(themis_secure_encrypted_message_hdr_t), NULL, &computed_length)); if(message==NULL || (*message_length)<computed_length){ (*message_length)=computed_length; return THEMIS_BUFFER_TOO_SMALL; } THEMIS_CHECK(themis_secure_cell_decrypt_seal(ctx->shared_secret, ctx->shared_secret_length, NULL,0,wrapped_message+sizeof(themis_secure_encrypted_message_hdr_t), wrapped_message_length-sizeof(themis_secure_encrypted_message_hdr_t), message, message_length)==THEMIS_SUCCESS); return THEMIS_SUCCESS; }
themis_status_t themis_secure_message_ec_encrypter_proceed(themis_secure_message_ec_t* ctx, const uint8_t* message, const size_t message_length, uint8_t* wrapped_message, size_t* wrapped_message_length){ THEMIS_CHECK_PARAM(ctx!=NULL); size_t encrypted_message_length=0; THEMIS_CHECK(themis_secure_cell_encrypt_seal(ctx->shared_secret, ctx->shared_secret_length, NULL, 0, message, message_length, NULL, &encrypted_message_length)==THEMIS_BUFFER_TOO_SMALL && encrypted_message_length!=0); if(wrapped_message==NULL || (*wrapped_message_length)<(sizeof(themis_secure_encrypted_message_hdr_t)+encrypted_message_length)){ (*wrapped_message_length)=(sizeof(themis_secure_encrypted_message_hdr_t)+encrypted_message_length); return THEMIS_BUFFER_TOO_SMALL; } themis_secure_encrypted_message_hdr_t* hdr=(themis_secure_encrypted_message_hdr_t*)wrapped_message; hdr->message_hdr.message_type=THEMIS_SECURE_MESSAGE_EC_ENCRYPTED; hdr->message_hdr.message_length=(uint32_t)(sizeof(themis_secure_encrypted_message_hdr_t)+encrypted_message_length); encrypted_message_length=(*wrapped_message_length)-sizeof(themis_secure_encrypted_message_hdr_t); THEMIS_CHECK(themis_secure_cell_encrypt_seal(ctx->shared_secret, ctx->shared_secret_length, NULL,0, message, message_length, wrapped_message+sizeof(themis_secure_encrypted_message_hdr_t), &encrypted_message_length)==THEMIS_SUCCESS); (*wrapped_message_length)=encrypted_message_length+sizeof(themis_secure_encrypted_message_hdr_t); return THEMIS_SUCCESS; }
themis_status_t themis_message_destroy(themis_message_t* ctx){ THEMIS_CHECK(ctx); if(ctx->data!=NULL){ free(ctx->data); } free(ctx); ctx=NULL; return THEMIS_SUCCESS; }
themis_status_t themis_message_set(themis_message_t* ctx, const uint8_t* message, const size_t message_length){ THEMIS_CHECK(ctx); THEMIS_CHECK(message); THEMIS_CHECK(message_length!=0); if(ctx->length<message_length){ if(!ctx){ ctx->data=malloc(message_length); } else { ctx->data=realloc(ctx->data, message_length); } if(!(ctx->data)){ ctx->length=0; return THEMIS_FAIL; } ctx->length=message_length; } memcpy(ctx->data, message, message_length); return THEMIS_SUCCESS; }
themis_status_t themis_secure_message_verifier_proceed(themis_secure_message_verifier_t* ctx, const uint8_t* wrapped_message, const size_t wrapped_message_length, uint8_t* message, size_t* message_length) { THEMIS_CHECK(ctx!=NULL); THEMIS_CHECK(wrapped_message!=NULL && wrapped_message_length!=0 && message_length!=NULL); themis_secure_signed_message_hdr_t* msg=(themis_secure_signed_message_hdr_t*)wrapped_message; if(((msg->message_hdr.message_type==THEMIS_SECURE_MESSAGE_RSA_SIGNED && soter_verify_get_alg_id(ctx->verify_ctx)!=SOTER_SIGN_rsa_pss_pkcs8) || (msg->message_hdr.message_type==THEMIS_SECURE_MESSAGE_EC_SIGNED && soter_verify_get_alg_id(ctx->verify_ctx)!=SOTER_SIGN_ecdsa_none_pkcs8)) && (msg->message_hdr.message_length+msg->signature_length+sizeof(themis_secure_message_hdr_t)>wrapped_message_length)){ return THEMIS_INVALID_PARAMETER; } if(message == NULL || (*message_length)<msg->message_hdr.message_length){ (*message_length)=msg->message_hdr.message_length; return THEMIS_BUFFER_TOO_SMALL; } THEMIS_CHECK(soter_verify_update(ctx->verify_ctx, wrapped_message+sizeof(themis_secure_signed_message_hdr_t), msg->message_hdr.message_length)==THEMIS_SUCCESS); THEMIS_CHECK(soter_verify_final(ctx->verify_ctx, wrapped_message+sizeof(themis_secure_signed_message_hdr_t)+msg->message_hdr.message_length, msg->signature_length)==THEMIS_SUCCESS); memcpy(message,wrapped_message+sizeof(themis_secure_signed_message_hdr_t),msg->message_hdr.message_length); (*message_length)=msg->message_hdr.message_length; return THEMIS_SUCCESS; }
themis_status_t themis_secure_message_decrypter_destroy(themis_secure_message_decrypter_t* ctx){ THEMIS_CHECK(ctx!=NULL); switch(ctx->alg){ case SOTER_SIGN_ecdsa_none_pkcs8: return themis_secure_message_ec_decrypter_destroy(ctx->ctx.ec_encrypter); case SOTER_SIGN_rsa_pss_pkcs8: return themis_secure_message_rsa_decrypter_destroy(ctx->ctx.rsa_encrypter); default: return THEMIS_FAIL; } return THEMIS_INVALID_PARAMETER;; }
themis_status_t themis_secure_message_decrypter_proceed(themis_secure_message_decrypter_t* ctx, const uint8_t* wrapped_message, const size_t wrapped_message_length, uint8_t* message, size_t* message_length){ THEMIS_CHECK(ctx!=NULL); switch(ctx->alg){ case SOTER_SIGN_ecdsa_none_pkcs8: return themis_secure_message_ec_decrypter_proceed(ctx->ctx.ec_encrypter, wrapped_message, wrapped_message_length, message, message_length); case SOTER_SIGN_rsa_pss_pkcs8: return themis_secure_message_rsa_decrypter_proceed(ctx->ctx.rsa_encrypter, wrapped_message, wrapped_message_length, message, message_length); default: return THEMIS_FAIL; } return THEMIS_FAIL; }
themis_status_t themis_secure_message_rsa_decrypter_proceed(themis_secure_message_rsa_decrypter_t* ctx, const uint8_t* wrapped_message, const size_t wrapped_message_length, uint8_t* message, size_t* message_length){ THEMIS_CHECK_PARAM(wrapped_message_length>sizeof(themis_secure_rsa_encrypted_message_hdr_t)); THEMIS_CHECK_PARAM(((const themis_secure_encrypted_message_hdr_t*)wrapped_message)->message_hdr.message_type==THEMIS_SECURE_MESSAGE_RSA_ENCRYPTED); THEMIS_CHECK_PARAM(((const themis_secure_encrypted_message_hdr_t*)wrapped_message)->message_hdr.message_length==wrapped_message_length); size_t ml=0; THEMIS_CHECK(themis_secure_cell_decrypt_seal((const uint8_t*)"123",3,NULL,0,wrapped_message+sizeof(themis_secure_rsa_encrypted_message_hdr_t)+((const themis_secure_rsa_encrypted_message_hdr_t*)wrapped_message)->encrypted_passwd_length, wrapped_message_length-sizeof(themis_secure_rsa_encrypted_message_hdr_t)-((const themis_secure_rsa_encrypted_message_hdr_t*)wrapped_message)->encrypted_passwd_length, NULL, &ml)==THEMIS_BUFFER_TOO_SMALL); if((message==NULL)||((*message_length)<ml)){ (*message_length)=ml; return THEMIS_BUFFER_TOO_SMALL; } uint8_t sym_ctx_buffer[1024]; size_t sym_ctx_length_=sizeof(sym_ctx_buffer); const uint8_t* wrapped_message_=wrapped_message; wrapped_message_+=sizeof(themis_secure_rsa_encrypted_message_hdr_t); size_t wrapped_message_length_=wrapped_message_length; wrapped_message_length_-=sizeof(themis_secure_rsa_encrypted_message_hdr_t); THEMIS_CHECK(soter_asym_cipher_decrypt(ctx->asym_cipher, wrapped_message_, ((const themis_secure_rsa_encrypted_message_hdr_t*)wrapped_message)->encrypted_passwd_length, sym_ctx_buffer, &sym_ctx_length_)==THEMIS_SUCCESS); wrapped_message_+=((const themis_secure_rsa_encrypted_message_hdr_t*)wrapped_message)->encrypted_passwd_length; wrapped_message_length_-=((const themis_secure_rsa_encrypted_message_hdr_t*)wrapped_message)->encrypted_passwd_length; THEMIS_CHECK(themis_secure_cell_decrypt_seal(sym_ctx_buffer,sym_ctx_length_,NULL,0,wrapped_message_, wrapped_message_length_, message, message_length)==THEMIS_SUCCESS); return THEMIS_SUCCESS; }
themis_status_t themis_secure_message_signer_proceed(themis_secure_message_signer_t* ctx, const uint8_t* message, const size_t message_length, uint8_t* wrapped_message, size_t* wrapped_message_length) { THEMIS_CHECK(ctx!=NULL && ctx->sign_ctx!=NULL); THEMIS_CHECK(message!=NULL && message_length!=0 && wrapped_message_length!=NULL); uint8_t* signature=NULL; size_t signature_length=0; THEMIS_CHECK(soter_sign_update(ctx->sign_ctx, message, message_length)==THEMIS_SUCCESS); THEMIS_CHECK(soter_sign_final(ctx->sign_ctx, signature, &signature_length)==THEMIS_BUFFER_TOO_SMALL); if(wrapped_message==NULL ||(message_length+signature_length+sizeof(themis_secure_signed_message_hdr_t)>(*wrapped_message_length))){ (*wrapped_message_length)=message_length+signature_length+sizeof(themis_secure_signed_message_hdr_t); return THEMIS_BUFFER_TOO_SMALL; } signature=malloc(signature_length); THEMIS_CHECK(signature!=NULL); if(soter_sign_final(ctx->sign_ctx, signature, &signature_length)!=THEMIS_SUCCESS){ free(signature); return THEMIS_FAIL; } themis_secure_signed_message_hdr_t hdr; switch(soter_sign_get_alg_id(ctx->sign_ctx)){ case SOTER_SIGN_ecdsa_none_pkcs8: hdr.message_hdr.message_type=THEMIS_SECURE_MESSAGE_EC_SIGNED; break; case SOTER_SIGN_rsa_pss_pkcs8: hdr.message_hdr.message_type=THEMIS_SECURE_MESSAGE_RSA_SIGNED; break; default: return THEMIS_INVALID_PARAMETER; }; hdr.message_hdr.message_length=(uint32_t)message_length; hdr.signature_length=(uint32_t)signature_length; memcpy(wrapped_message,&hdr,sizeof(themis_secure_signed_message_hdr_t)); memcpy(wrapped_message+sizeof(themis_secure_signed_message_hdr_t),message,message_length); memcpy(wrapped_message+sizeof(themis_secure_signed_message_hdr_t)+message_length,signature,signature_length); (*wrapped_message_length)=message_length+signature_length+sizeof(themis_secure_signed_message_hdr_t); return THEMIS_SUCCESS; }
themis_status_t themis_secure_message_unwrap(const uint8_t* private_key, const size_t private_key_length, const uint8_t* public_key, const size_t public_key_length, const uint8_t* wrapped_message, const size_t wrapped_message_length, uint8_t* message, size_t* message_length){ THEMIS_CHECK_PARAM(public_key!=NULL); THEMIS_CHECK_PARAM(public_key_length!=0); THEMIS_CHECK_PARAM(wrapped_message!=NULL); THEMIS_CHECK_PARAM(wrapped_message_length!=0); THEMIS_CHECK_PARAM(message_length!=NULL); themis_secure_message_hdr_t* message_hdr=(themis_secure_message_hdr_t*)wrapped_message; THEMIS_CHECK_PARAM(IS_THEMIS_SECURE_MESSAGE_SIGNED(message_hdr->message_type) || IS_THEMIS_SECURE_MESSAGE_ENCRYPTED(message_hdr->message_type)); THEMIS_CHECK_PARAM(wrapped_message_length>=THEMIS_SECURE_MESSAGE_LENGTH(message_hdr)); if(IS_THEMIS_SECURE_MESSAGE_SIGNED(message_hdr->message_type)){ themis_secure_message_verifier_t* ctx=NULL; ctx = themis_secure_message_verifier_init(public_key, public_key_length); THEMIS_CHECK(ctx!=NULL); themis_status_t res=themis_secure_message_verifier_proceed(ctx, wrapped_message, wrapped_message_length, message, message_length); themis_secure_message_verifier_destroy(ctx); return res; } else{ THEMIS_CHECK_PARAM(private_key!=NULL); THEMIS_CHECK_PARAM(private_key_length!=0); themis_secure_message_decrypter_t* ctx=NULL; ctx = themis_secure_message_decrypter_init(private_key, private_key_length, public_key, public_key_length); THEMIS_CHECK(ctx!=NULL); themis_status_t res=themis_secure_message_decrypter_proceed(ctx, wrapped_message, wrapped_message_length, message, message_length); themis_secure_message_decrypter_destroy(ctx); return res; } return THEMIS_INVALID_PARAMETER; }
themis_status_t themis_secure_message_rsa_encrypter_proceed(themis_secure_message_rsa_encrypter_t* ctx, const uint8_t* message, const size_t message_length, uint8_t* wrapped_message, size_t* wrapped_message_length){ size_t symm_passwd_length=0; size_t seal_message_length=0; THEMIS_CHECK(soter_asym_cipher_encrypt(ctx->asym_cipher, (const uint8_t*)"123", 3, NULL, &symm_passwd_length)==THEMIS_BUFFER_TOO_SMALL); THEMIS_CHECK(themis_secure_cell_encrypt_seal((const uint8_t*)"123", 3, NULL, 0, message, message_length, NULL, &seal_message_length)==THEMIS_BUFFER_TOO_SMALL); if(wrapped_message==NULL || (*wrapped_message_length)<(sizeof(themis_secure_rsa_encrypted_message_hdr_t)+symm_passwd_length+seal_message_length)){ (*wrapped_message_length)=(sizeof(themis_secure_rsa_encrypted_message_hdr_t)+symm_passwd_length+seal_message_length); return THEMIS_BUFFER_TOO_SMALL; } // symm_init_ctx_t symm_passwd_salt; uint8_t symm_passwd[THEMIS_RSA_SYMM_PASSWD_LENGTH]; THEMIS_CHECK(soter_rand(symm_passwd, sizeof(symm_passwd))==THEMIS_SUCCESS); uint8_t* encrypted_symm_pass=wrapped_message+sizeof(themis_secure_rsa_encrypted_message_hdr_t); size_t encrypted_symm_pass_length=symm_passwd_length; THEMIS_CHECK(soter_asym_cipher_encrypt(ctx->asym_cipher, symm_passwd, sizeof(symm_passwd), encrypted_symm_pass, &encrypted_symm_pass_length)==THEMIS_SUCCESS); (((themis_secure_rsa_encrypted_message_hdr_t*)wrapped_message)->encrypted_passwd_length)=(uint32_t)encrypted_symm_pass_length; uint8_t* encrypted_message=encrypted_symm_pass+encrypted_symm_pass_length; size_t encrypted_message_length=seal_message_length; THEMIS_CHECK(themis_secure_cell_encrypt_seal(symm_passwd, sizeof(symm_passwd), NULL, 0, message, message_length, encrypted_message, &encrypted_message_length)==THEMIS_SUCCESS); (*wrapped_message_length)=sizeof(themis_secure_rsa_encrypted_message_hdr_t)+encrypted_symm_pass_length+encrypted_message_length; ((themis_secure_encrypted_message_hdr_t*)wrapped_message)->message_hdr.message_type=THEMIS_SECURE_MESSAGE_RSA_ENCRYPTED; ((themis_secure_encrypted_message_hdr_t*)wrapped_message)->message_hdr.message_length=(uint32_t)(*wrapped_message_length); return THEMIS_SUCCESS; }
themis_status_t themis_gen_key_pair(soter_sign_alg_t alg, uint8_t* private_key, size_t* private_key_length, uint8_t* public_key, size_t* public_key_length) { soter_sign_ctx_t* ctx=soter_sign_create(alg,NULL,0,NULL,0); THEMIS_CHECK(ctx!=NULL); soter_status_t res=soter_sign_export_key(ctx, private_key, private_key_length, true); if(res!=THEMIS_SUCCESS && res != THEMIS_BUFFER_TOO_SMALL){ soter_sign_destroy(ctx); return res; } soter_status_t res2=soter_sign_export_key(ctx, public_key, public_key_length, false); if(res2!=THEMIS_SUCCESS && res2!=THEMIS_BUFFER_TOO_SMALL){ soter_sign_destroy(ctx); return res; } soter_sign_destroy(ctx); if(res==THEMIS_BUFFER_TOO_SMALL || res2==THEMIS_BUFFER_TOO_SMALL){ return THEMIS_BUFFER_TOO_SMALL; } return THEMIS_SUCCESS; }