You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
358 lines
7.8 KiB
358 lines
7.8 KiB
/*
|
|
* cipher.cpp - Simple wrapper to 3DES,AES128/256 CBC ciphers
|
|
* Copyright (C) 2003 Justin Karneges
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library 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
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*
|
|
*/
|
|
|
|
#include "cipher.h"
|
|
|
|
#include <openssl/evp.h>
|
|
#include <openssl/rsa.h>
|
|
#include "bytestream.h"
|
|
#include "tqrandom.h"
|
|
|
|
static bool lib_encryptArray(const EVP_CIPHER *type, const TQByteArray &buf, const TQByteArray &key, const TQByteArray &iv, bool pad, TQByteArray *out)
|
|
{
|
|
TQByteArray result(buf.size()+type->block_size);
|
|
int len;
|
|
EVP_CIPHER_CTX c;
|
|
|
|
unsigned char *ivp = NULL;
|
|
if(!iv.isEmpty())
|
|
ivp = (unsigned char *)iv.data();
|
|
EVP_CIPHER_CTX_init(&c);
|
|
//EVP_CIPHER_CTX_set_padding(&c, pad ? 1: 0);
|
|
if(!EVP_EncryptInit_ex(&c, type, NULL, (unsigned char *)key.data(), ivp))
|
|
return false;
|
|
if(!EVP_EncryptUpdate(&c, (unsigned char *)result.data(), &len, (unsigned char *)buf.data(), buf.size()))
|
|
return false;
|
|
result.resize(len);
|
|
if(pad) {
|
|
TQByteArray last(type->block_size);
|
|
if(!EVP_EncryptFinal_ex(&c, (unsigned char *)last.data(), &len))
|
|
return false;
|
|
last.resize(len);
|
|
ByteStream::appendArray(&result, last);
|
|
}
|
|
|
|
memset(&c, 0, sizeof(EVP_CIPHER_CTX));
|
|
*out = result;
|
|
return true;
|
|
}
|
|
|
|
static bool lib_decryptArray(const EVP_CIPHER *type, const TQByteArray &buf, const TQByteArray &key, const TQByteArray &iv, bool pad, TQByteArray *out)
|
|
{
|
|
TQByteArray result(buf.size()+type->block_size);
|
|
int len;
|
|
EVP_CIPHER_CTX c;
|
|
|
|
unsigned char *ivp = NULL;
|
|
if(!iv.isEmpty())
|
|
ivp = (unsigned char *)iv.data();
|
|
EVP_CIPHER_CTX_init(&c);
|
|
//EVP_CIPHER_CTX_set_padding(&c, pad ? 1: 0);
|
|
if(!EVP_DecryptInit_ex(&c, type, NULL, (unsigned char *)key.data(), ivp))
|
|
return false;
|
|
if(!pad) {
|
|
if(!EVP_EncryptUpdate(&c, (unsigned char *)result.data(), &len, (unsigned char *)buf.data(), buf.size()))
|
|
return false;
|
|
}
|
|
else {
|
|
if(!EVP_DecryptUpdate(&c, (unsigned char *)result.data(), &len, (unsigned char *)buf.data(), buf.size()))
|
|
return false;
|
|
}
|
|
result.resize(len);
|
|
if(pad) {
|
|
TQByteArray last(type->block_size);
|
|
if(!EVP_DecryptFinal_ex(&c, (unsigned char *)last.data(), &len))
|
|
return false;
|
|
last.resize(len);
|
|
ByteStream::appendArray(&result, last);
|
|
}
|
|
|
|
memset(&c, 0, sizeof(EVP_CIPHER_CTX));
|
|
*out = result;
|
|
return true;
|
|
}
|
|
|
|
static bool lib_generateKeyIV(const EVP_CIPHER *type, const TQByteArray &data, const TQByteArray &salt, TQByteArray *key, TQByteArray *iv)
|
|
{
|
|
TQByteArray k, i;
|
|
unsigned char *kp = 0;
|
|
unsigned char *ip = 0;
|
|
if(key) {
|
|
k.resize(type->key_len);
|
|
kp = (unsigned char *)k.data();
|
|
}
|
|
if(iv) {
|
|
i.resize(type->iv_len);
|
|
ip = (unsigned char *)i.data();
|
|
}
|
|
if(!EVP_BytesToKey(type, EVP_sha1(), (unsigned char *)salt.data(), (unsigned char *)data.data(), data.size(), 1, kp, ip))
|
|
return false;
|
|
if(key)
|
|
*key = k;
|
|
if(iv)
|
|
*iv = i;
|
|
return true;
|
|
}
|
|
|
|
static const EVP_CIPHER * typeToCIPHER(Cipher::Type t)
|
|
{
|
|
if(t == Cipher::TripleDES)
|
|
return EVP_des_ede3_cbc();
|
|
else if(t == Cipher::AES_128)
|
|
return EVP_aes_128_cbc();
|
|
else if(t == Cipher::AES_256)
|
|
return EVP_aes_256_cbc();
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
Cipher::Key Cipher::generateKey(Type t)
|
|
{
|
|
Key k;
|
|
const EVP_CIPHER *type = typeToCIPHER(t);
|
|
if(!type)
|
|
return k;
|
|
TQByteArray out;
|
|
if(!lib_generateKeyIV(type, TQRandom::randomArray(128), TQRandom::randomArray(2), &out, 0))
|
|
return k;
|
|
k.setType(t);
|
|
k.setData(out);
|
|
return k;
|
|
}
|
|
|
|
TQByteArray Cipher::generateIV(Type t)
|
|
{
|
|
const EVP_CIPHER *type = typeToCIPHER(t);
|
|
if(!type)
|
|
return TQByteArray();
|
|
TQByteArray out;
|
|
if(!lib_generateKeyIV(type, TQCString("Get this man an iv!"), TQByteArray(), 0, &out))
|
|
return TQByteArray();
|
|
return out;
|
|
}
|
|
|
|
int Cipher::ivSize(Type t)
|
|
{
|
|
const EVP_CIPHER *type = typeToCIPHER(t);
|
|
if(!type)
|
|
return -1;
|
|
return type->iv_len;
|
|
}
|
|
|
|
TQByteArray Cipher::encrypt(const TQByteArray &buf, const Key &key, const TQByteArray &iv, bool pad, bool *ok)
|
|
{
|
|
if(ok)
|
|
*ok = false;
|
|
const EVP_CIPHER *type = typeToCIPHER(key.type());
|
|
if(!type)
|
|
return TQByteArray();
|
|
TQByteArray out;
|
|
if(!lib_encryptArray(type, buf, key.data(), iv, pad, &out))
|
|
return TQByteArray();
|
|
|
|
if(ok)
|
|
*ok = true;
|
|
return out;
|
|
}
|
|
|
|
TQByteArray Cipher::decrypt(const TQByteArray &buf, const Key &key, const TQByteArray &iv, bool pad, bool *ok)
|
|
{
|
|
if(ok)
|
|
*ok = false;
|
|
const EVP_CIPHER *type = typeToCIPHER(key.type());
|
|
if(!type)
|
|
return TQByteArray();
|
|
TQByteArray out;
|
|
if(!lib_decryptArray(type, buf, key.data(), iv, pad, &out))
|
|
return TQByteArray();
|
|
|
|
if(ok)
|
|
*ok = true;
|
|
return out;
|
|
}
|
|
|
|
|
|
class RSAKey::Private
|
|
{
|
|
public:
|
|
Private() {}
|
|
|
|
RSA *rsa;
|
|
int ref;
|
|
};
|
|
|
|
RSAKey::RSAKey()
|
|
{
|
|
d = 0;
|
|
}
|
|
|
|
RSAKey::RSAKey(const RSAKey &from)
|
|
{
|
|
d = 0;
|
|
*this = from;
|
|
}
|
|
|
|
RSAKey & RSAKey::operator=(const RSAKey &from)
|
|
{
|
|
free();
|
|
|
|
if(from.d) {
|
|
d = from.d;
|
|
++d->ref;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
RSAKey::~RSAKey()
|
|
{
|
|
free();
|
|
}
|
|
|
|
bool RSAKey::isNull() const
|
|
{
|
|
return d ? false: true;
|
|
}
|
|
|
|
void * RSAKey::data() const
|
|
{
|
|
if(d)
|
|
return (void *)d->rsa;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
void RSAKey::setData(void *p)
|
|
{
|
|
free();
|
|
|
|
if(p) {
|
|
d = new Private;
|
|
d->ref = 1;
|
|
d->rsa = (RSA *)p;
|
|
}
|
|
}
|
|
|
|
void RSAKey::free()
|
|
{
|
|
if(!d)
|
|
return;
|
|
|
|
--d->ref;
|
|
if(d->ref <= 0) {
|
|
RSA_free(d->rsa);
|
|
delete d;
|
|
}
|
|
d = 0;
|
|
}
|
|
|
|
RSAKey generateRSAKey()
|
|
{
|
|
RSA *rsa = RSA_generate_key(1024, RSA_F4, NULL, NULL);
|
|
RSAKey key;
|
|
if(rsa)
|
|
key.setData(rsa);
|
|
return key;
|
|
}
|
|
|
|
TQByteArray encryptRSA(const TQByteArray &buf, const RSAKey &key, bool *ok)
|
|
{
|
|
if(ok)
|
|
*ok = false;
|
|
|
|
int size = RSA_size((RSA *)key.data());
|
|
int flen = buf.size();
|
|
if(flen >= size - 11)
|
|
flen = size - 11;
|
|
TQByteArray result(size);
|
|
unsigned char *from = (unsigned char *)buf.data();
|
|
unsigned char *to = (unsigned char *)result.data();
|
|
int r = RSA_public_encrypt(flen, from, to, (RSA *)key.data(), RSA_PKCS1_PADDING);
|
|
if(r == -1)
|
|
return TQByteArray();
|
|
result.resize(r);
|
|
|
|
if(ok)
|
|
*ok = true;
|
|
return result;
|
|
}
|
|
|
|
TQByteArray decryptRSA(const TQByteArray &buf, const RSAKey &key, bool *ok)
|
|
{
|
|
if(ok)
|
|
*ok = false;
|
|
|
|
int size = RSA_size((RSA *)key.data());
|
|
int flen = buf.size();
|
|
TQByteArray result(size);
|
|
unsigned char *from = (unsigned char *)buf.data();
|
|
unsigned char *to = (unsigned char *)result.data();
|
|
int r = RSA_private_decrypt(flen, from, to, (RSA *)key.data(), RSA_PKCS1_PADDING);
|
|
if(r == -1)
|
|
return TQByteArray();
|
|
result.resize(r);
|
|
|
|
if(ok)
|
|
*ok = true;
|
|
return result;
|
|
}
|
|
|
|
TQByteArray encryptRSA2(const TQByteArray &buf, const RSAKey &key, bool *ok)
|
|
{
|
|
if(ok)
|
|
*ok = false;
|
|
|
|
int size = RSA_size((RSA *)key.data());
|
|
int flen = buf.size();
|
|
if(flen >= size - 41)
|
|
flen = size - 41;
|
|
TQByteArray result(size);
|
|
unsigned char *from = (unsigned char *)buf.data();
|
|
unsigned char *to = (unsigned char *)result.data();
|
|
int r = RSA_public_encrypt(flen, from, to, (RSA *)key.data(), RSA_PKCS1_OAEP_PADDING);
|
|
if(r == -1)
|
|
return TQByteArray();
|
|
result.resize(r);
|
|
|
|
if(ok)
|
|
*ok = true;
|
|
return result;
|
|
}
|
|
|
|
TQByteArray decryptRSA2(const TQByteArray &buf, const RSAKey &key, bool *ok)
|
|
{
|
|
if(ok)
|
|
*ok = false;
|
|
|
|
int size = RSA_size((RSA *)key.data());
|
|
int flen = buf.size();
|
|
TQByteArray result(size);
|
|
unsigned char *from = (unsigned char *)buf.data();
|
|
unsigned char *to = (unsigned char *)result.data();
|
|
int r = RSA_private_decrypt(flen, from, to, (RSA *)key.data(), RSA_PKCS1_OAEP_PADDING);
|
|
if(r == -1)
|
|
return TQByteArray();
|
|
result.resize(r);
|
|
|
|
if(ok)
|
|
*ok = true;
|
|
return result;
|
|
}
|