307 lines
6.0 KiB
C
307 lines
6.0 KiB
C
/*
|
|
* Copyright (C) 2009 Martin Willi
|
|
* Hochschule fuer Technik Rapperswil
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the
|
|
* Free Software Foundation; either version 2 of the License, or (at your
|
|
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* for more details.
|
|
*/
|
|
|
|
#include "gcrypt_crypter.h"
|
|
|
|
#include <gcrypt.h>
|
|
|
|
#include <debug.h>
|
|
|
|
typedef struct private_gcrypt_crypter_t private_gcrypt_crypter_t;
|
|
|
|
/**
|
|
* Private data of gcrypt_crypter_t
|
|
*/
|
|
struct private_gcrypt_crypter_t {
|
|
|
|
/**
|
|
* Public part of this class.
|
|
*/
|
|
gcrypt_crypter_t public;
|
|
|
|
/**
|
|
* gcrypt cipher handle
|
|
*/
|
|
gcry_cipher_hd_t h;
|
|
|
|
/**
|
|
* gcrypt algorithm identifier
|
|
*/
|
|
int alg;
|
|
|
|
/**
|
|
* are we using counter mode?
|
|
*/
|
|
bool ctr_mode;
|
|
|
|
/**
|
|
* counter state
|
|
*/
|
|
struct {
|
|
char nonce[4];
|
|
char iv[8];
|
|
u_int32_t counter;
|
|
} __attribute__((packed)) ctr;
|
|
};
|
|
|
|
/**
|
|
* Set the IV for en/decryption
|
|
*/
|
|
static void set_iv(private_gcrypt_crypter_t *this, chunk_t iv)
|
|
{
|
|
if (this->ctr_mode)
|
|
{
|
|
memcpy(this->ctr.iv, iv.ptr, sizeof(this->ctr.iv));
|
|
this->ctr.counter = htonl(1);
|
|
gcry_cipher_setctr(this->h, &this->ctr, sizeof(this->ctr));
|
|
}
|
|
else
|
|
{
|
|
gcry_cipher_setiv(this->h, iv.ptr, iv.len);
|
|
}
|
|
}
|
|
|
|
METHOD(crypter_t, decrypt, void,
|
|
private_gcrypt_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *dst)
|
|
{
|
|
set_iv(this, iv);
|
|
|
|
if (dst)
|
|
{
|
|
*dst = chunk_alloc(data.len);
|
|
gcry_cipher_decrypt(this->h, dst->ptr, dst->len, data.ptr, data.len);
|
|
}
|
|
else
|
|
{
|
|
gcry_cipher_decrypt(this->h, data.ptr, data.len, NULL, 0);
|
|
}
|
|
}
|
|
|
|
METHOD(crypter_t, encrypt, void,
|
|
private_gcrypt_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *dst)
|
|
{
|
|
set_iv(this, iv);
|
|
|
|
if (dst)
|
|
{
|
|
*dst = chunk_alloc(data.len);
|
|
gcry_cipher_encrypt(this->h, dst->ptr, dst->len, data.ptr, data.len);
|
|
}
|
|
else
|
|
{
|
|
gcry_cipher_encrypt(this->h, data.ptr, data.len, NULL, 0);
|
|
}
|
|
}
|
|
|
|
METHOD(crypter_t, get_block_size, size_t,
|
|
private_gcrypt_crypter_t *this)
|
|
{
|
|
size_t len = 0;
|
|
|
|
if (this->ctr_mode)
|
|
{ /* counter mode does not need any padding */
|
|
return 1;
|
|
}
|
|
gcry_cipher_algo_info(this->alg, GCRYCTL_GET_BLKLEN, NULL, &len);
|
|
return len;
|
|
}
|
|
|
|
METHOD(crypter_t, get_iv_size, size_t,
|
|
private_gcrypt_crypter_t *this)
|
|
{
|
|
size_t len = 0;
|
|
|
|
if (this->ctr_mode)
|
|
{
|
|
return sizeof(this->ctr.iv);
|
|
}
|
|
gcry_cipher_algo_info(this->alg, GCRYCTL_GET_BLKLEN, NULL, &len);
|
|
return len;
|
|
}
|
|
|
|
METHOD(crypter_t, get_key_size, size_t,
|
|
private_gcrypt_crypter_t *this)
|
|
{
|
|
size_t len = 0;
|
|
|
|
gcry_cipher_algo_info(this->alg, GCRYCTL_GET_KEYLEN, NULL, &len);
|
|
if (this->ctr_mode)
|
|
{
|
|
return len + sizeof(this->ctr.nonce);
|
|
}
|
|
return len;
|
|
}
|
|
|
|
METHOD(crypter_t, set_key, void,
|
|
private_gcrypt_crypter_t *this, chunk_t key)
|
|
{
|
|
if (this->ctr_mode)
|
|
{
|
|
/* last 4 bytes are the nonce */
|
|
memcpy(this->ctr.nonce, key.ptr + key.len - sizeof(this->ctr.nonce),
|
|
sizeof(this->ctr.nonce));
|
|
key.len -= sizeof(this->ctr.nonce);
|
|
}
|
|
gcry_cipher_setkey(this->h, key.ptr, key.len);
|
|
}
|
|
|
|
METHOD(crypter_t, destroy, void,
|
|
private_gcrypt_crypter_t *this)
|
|
{
|
|
gcry_cipher_close(this->h);
|
|
free(this);
|
|
}
|
|
|
|
/*
|
|
* Described in header
|
|
*/
|
|
gcrypt_crypter_t *gcrypt_crypter_create(encryption_algorithm_t algo,
|
|
size_t key_size)
|
|
{
|
|
private_gcrypt_crypter_t *this;
|
|
int gcrypt_alg;
|
|
int mode = GCRY_CIPHER_MODE_CBC;
|
|
gcry_error_t err;
|
|
|
|
switch (algo)
|
|
{
|
|
case ENCR_DES:
|
|
gcrypt_alg = GCRY_CIPHER_DES;
|
|
break;
|
|
case ENCR_DES_ECB:
|
|
gcrypt_alg = GCRY_CIPHER_DES;
|
|
mode = GCRY_CIPHER_MODE_ECB;
|
|
break;
|
|
case ENCR_3DES:
|
|
gcrypt_alg = GCRY_CIPHER_3DES;
|
|
break;
|
|
case ENCR_IDEA:
|
|
/* currently not implemented in gcrypt */
|
|
return NULL;
|
|
case ENCR_CAST:
|
|
gcrypt_alg = GCRY_CIPHER_CAST5;
|
|
break;
|
|
case ENCR_BLOWFISH:
|
|
if (key_size != 16 && key_size != 0)
|
|
{ /* gcrypt currently supports 128 bit blowfish only */
|
|
return NULL;
|
|
}
|
|
gcrypt_alg = GCRY_CIPHER_BLOWFISH;
|
|
break;
|
|
case ENCR_AES_CTR:
|
|
mode = GCRY_CIPHER_MODE_CTR;
|
|
/* fall */
|
|
case ENCR_AES_CBC:
|
|
switch (key_size)
|
|
{
|
|
case 0:
|
|
case 16:
|
|
gcrypt_alg = GCRY_CIPHER_AES128;
|
|
break;
|
|
case 24:
|
|
gcrypt_alg = GCRY_CIPHER_AES192;
|
|
break;
|
|
case 32:
|
|
gcrypt_alg = GCRY_CIPHER_AES256;
|
|
break;
|
|
default:
|
|
return NULL;
|
|
}
|
|
break;
|
|
case ENCR_CAMELLIA_CTR:
|
|
mode = GCRY_CIPHER_MODE_CTR;
|
|
/* fall */
|
|
case ENCR_CAMELLIA_CBC:
|
|
switch (key_size)
|
|
{
|
|
#ifdef HAVE_GCRY_CIPHER_CAMELLIA
|
|
case 0:
|
|
case 16:
|
|
gcrypt_alg = GCRY_CIPHER_CAMELLIA128;
|
|
break;
|
|
case 24:
|
|
gcrypt_alg = GCRY_CIPHER_CAMELLIA192;
|
|
break;
|
|
case 32:
|
|
gcrypt_alg = GCRY_CIPHER_CAMELLIA256;
|
|
break;
|
|
#endif /* HAVE_GCRY_CIPHER_CAMELLIA */
|
|
default:
|
|
return NULL;
|
|
}
|
|
break;
|
|
case ENCR_SERPENT_CBC:
|
|
switch (key_size)
|
|
{
|
|
case 0:
|
|
case 16:
|
|
gcrypt_alg = GCRY_CIPHER_SERPENT128;
|
|
break;
|
|
case 24:
|
|
gcrypt_alg = GCRY_CIPHER_SERPENT192;
|
|
break;
|
|
case 32:
|
|
gcrypt_alg = GCRY_CIPHER_SERPENT256;
|
|
break;
|
|
default:
|
|
return NULL;
|
|
}
|
|
break;
|
|
case ENCR_TWOFISH_CBC:
|
|
switch (key_size)
|
|
{
|
|
case 0:
|
|
case 16:
|
|
gcrypt_alg = GCRY_CIPHER_TWOFISH128;
|
|
break;
|
|
case 32:
|
|
gcrypt_alg = GCRY_CIPHER_TWOFISH;
|
|
break;
|
|
default:
|
|
return NULL;
|
|
}
|
|
break;
|
|
default:
|
|
return NULL;
|
|
}
|
|
|
|
INIT(this,
|
|
.public = {
|
|
.crypter = {
|
|
.encrypt = _encrypt,
|
|
.decrypt = _decrypt,
|
|
.get_block_size = _get_block_size,
|
|
.get_iv_size = _get_iv_size,
|
|
.get_key_size = _get_key_size,
|
|
.set_key = _set_key,
|
|
.destroy = _destroy,
|
|
},
|
|
},
|
|
.alg = gcrypt_alg,
|
|
.ctr_mode = mode == GCRY_CIPHER_MODE_CTR,
|
|
);
|
|
|
|
err = gcry_cipher_open(&this->h, gcrypt_alg, mode, 0);
|
|
if (err)
|
|
{
|
|
DBG1(DBG_LIB, "grcy_cipher_open(%N) failed: %s",
|
|
encryption_algorithm_names, algo, gpg_strerror(err));
|
|
free(this);
|
|
return NULL;
|
|
}
|
|
return &this->public;
|
|
}
|
|
|