1
0
mirror of https://github.com/haiwen/seafile-server.git synced 2025-04-29 11:54:45 +00:00
seafile-server/common/block-tx-utils.c
2018-05-13 23:48:36 -07:00

297 lines
8.0 KiB
C

#include "common.h"
#define DEBUG_FLAG SEAFILE_DEBUG_TRANSFER
#include "log.h"
#include "utils.h"
#include "block-tx-utils.h"
/* Utility functions for block transfer protocol. */
/* Encryption related functions. */
void
blocktx_generate_encrypt_key (unsigned char *session_key, int sk_len,
unsigned char *key, unsigned char *iv)
{
EVP_BytesToKey (EVP_aes_256_cbc(), /* cipher mode */
EVP_sha1(), /* message digest */
NULL, /* salt */
session_key,
sk_len,
3, /* iteration times */
key, /* the derived key */
iv); /* IV, initial vector */
}
int
blocktx_encrypt_init (EVP_CIPHER_CTX **ctx,
const unsigned char *key,
const unsigned char *iv)
{
int ret;
/* Prepare CTX for encryption. */
*ctx = EVP_CIPHER_CTX_new ();
ret = EVP_EncryptInit_ex (*ctx,
EVP_aes_256_cbc(), /* cipher mode */
NULL, /* engine, NULL for default */
key, /* derived key */
iv); /* initial vector */
if (ret == 0)
return -1;
return 0;
}
int
blocktx_decrypt_init (EVP_CIPHER_CTX **ctx,
const unsigned char *key,
const unsigned char *iv)
{
int ret;
/* Prepare CTX for decryption. */
*ctx = EVP_CIPHER_CTX_new();
ret = EVP_DecryptInit_ex (*ctx,
EVP_aes_256_cbc(), /* cipher mode */
NULL, /* engine, NULL for default */
key, /* derived key */
iv); /* initial vector */
if (ret == 0)
return -1;
return 0;
}
/* Sending frame */
int
send_encrypted_data_frame_begin (evutil_socket_t data_fd,
int frame_len)
{
/* Compute data size after encryption.
* Block size is 16 bytes and AES always add one padding block.
*/
int enc_frame_len;
enc_frame_len = ((frame_len >> 4) + 1) << 4;
enc_frame_len = htonl (enc_frame_len);
if (sendn (data_fd, &enc_frame_len, sizeof(int)) < 0) {
seaf_warning ("Failed to send frame length: %s.\n",
evutil_socket_error_to_string(evutil_socket_geterror(data_fd)));
return -1;
}
return 0;
}
int
send_encrypted_data (EVP_CIPHER_CTX *ctx,
evutil_socket_t data_fd,
const void *buf, int len)
{
char out_buf[len + ENC_BLOCK_SIZE];
int out_len;
if (EVP_EncryptUpdate (ctx,
(unsigned char *)out_buf, &out_len,
(unsigned char *)buf, len) == 0) {
seaf_warning ("Failed to encrypt data.\n");
return -1;
}
if (sendn (data_fd, out_buf, out_len) < 0) {
seaf_warning ("Failed to write data: %s.\n",
evutil_socket_error_to_string(evutil_socket_geterror(data_fd)));
return -1;
}
return 0;
}
int
send_encrypted_data_frame_end (EVP_CIPHER_CTX *ctx,
evutil_socket_t data_fd)
{
char out_buf[ENC_BLOCK_SIZE];
int out_len;
if (EVP_EncryptFinal_ex (ctx, (unsigned char *)out_buf, &out_len) == 0) {
seaf_warning ("Failed to encrypt data.\n");
return -1;
}
if (sendn (data_fd, out_buf, out_len) < 0) {
seaf_warning ("Failed to write data: %s.\n",
evutil_socket_error_to_string(evutil_socket_geterror(data_fd)));
return -1;
}
return 0;
}
/* Receiving frame */
static int
handle_frame_content (struct evbuffer *buf, FrameParser *parser)
{
char *frame;
EVP_CIPHER_CTX *ctx;
char *out;
int outlen, outlen2;
int ret = 0;
struct evbuffer *input = buf;
if (evbuffer_get_length (input) < parser->enc_frame_len)
return 0;
if (parser->version == 1)
blocktx_decrypt_init (&ctx, parser->key, parser->iv);
else if (parser->version == 2)
blocktx_decrypt_init (&ctx, parser->key_v2, parser->iv_v2);
frame = g_malloc (parser->enc_frame_len);
out = g_malloc (parser->enc_frame_len + ENC_BLOCK_SIZE);
evbuffer_remove (input, frame, parser->enc_frame_len);
if (EVP_DecryptUpdate (ctx,
(unsigned char *)out, &outlen,
(unsigned char *)frame,
parser->enc_frame_len) == 0) {
seaf_warning ("Failed to decrypt frame content.\n");
ret = -1;
goto out;
}
if (EVP_DecryptFinal_ex (ctx, (unsigned char *)(out + outlen), &outlen2) == 0)
{
seaf_warning ("Failed to decrypt frame content.\n");
ret = -1;
goto out;
}
ret = parser->content_cb (out, outlen + outlen2, parser->cbarg);
out:
g_free (frame);
g_free (out);
parser->enc_frame_len = 0;
EVP_CIPHER_CTX_free (ctx);
return ret;
}
int
handle_one_frame (struct evbuffer *buf, FrameParser *parser)
{
struct evbuffer *input = buf;
if (!parser->enc_frame_len) {
/* Read the length of the encrypted frame first. */
if (evbuffer_get_length (input) < sizeof(int))
return 0;
int frame_len;
evbuffer_remove (input, &frame_len, sizeof(int));
parser->enc_frame_len = ntohl (frame_len);
if (evbuffer_get_length (input) > 0)
return handle_frame_content (buf, parser);
return 0;
} else {
return handle_frame_content (buf, parser);
}
}
static int
handle_frame_fragment_content (struct evbuffer *buf, FrameParser *parser)
{
char *fragment = NULL, *out = NULL;
int fragment_len, outlen;
int ret = 0;
struct evbuffer *input = buf;
fragment_len = evbuffer_get_length (input);
fragment = g_malloc (fragment_len);
evbuffer_remove (input, fragment, fragment_len);
out = g_malloc (fragment_len + ENC_BLOCK_SIZE);
if (EVP_DecryptUpdate (parser->ctx,
(unsigned char *)out, &outlen,
(unsigned char *)fragment, fragment_len) == 0) {
seaf_warning ("Failed to decrypt frame fragment.\n");
ret = -1;
goto out;
}
ret = parser->fragment_cb (out, outlen, 0, parser->cbarg);
if (ret < 0)
goto out;
parser->remain -= fragment_len;
if (parser->remain <= 0) {
if (EVP_DecryptFinal_ex (parser->ctx,
(unsigned char *)out,
&outlen) == 0) {
seaf_warning ("Failed to decrypt frame fragment.\n");
ret = -1;
goto out;
}
ret = parser->fragment_cb (out, outlen, 1, parser->cbarg);
if (ret < 0)
goto out;
EVP_CIPHER_CTX_free (parser->ctx);
parser->enc_init = FALSE;
parser->enc_frame_len = 0;
}
out:
g_free (fragment);
g_free (out);
if (ret < 0) {
EVP_CIPHER_CTX_free (parser->ctx);
parser->enc_init = FALSE;
parser->enc_frame_len = 0;
}
return ret;
}
int
handle_frame_fragments (struct evbuffer *buf, FrameParser *parser)
{
struct evbuffer *input = buf;
if (!parser->enc_frame_len) {
/* Read the length of the encrypted frame first. */
if (evbuffer_get_length (input) < sizeof(int))
return 0;
int frame_len;
evbuffer_remove (input, &frame_len, sizeof(int));
parser->enc_frame_len = ntohl (frame_len);
parser->remain = parser->enc_frame_len;
if (parser->version == 1)
blocktx_decrypt_init (&parser->ctx, parser->key, parser->iv);
else if (parser->version == 2)
blocktx_decrypt_init (&parser->ctx, parser->key_v2, parser->iv_v2);
parser->enc_init = TRUE;
if (evbuffer_get_length (input) > 0)
return handle_frame_fragment_content (buf, parser);
return 0;
} else {
return handle_frame_fragment_content (buf, parser);
}
}