mirror of
https://github.com/RetroShare/RetroShare.git
synced 2025-05-13 11:32:48 -04:00

git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@8490 b45a01b8-16f6-495d-af2f-9b41ad6348cc
819 lines
20 KiB
C
819 lines
20 KiB
C
/*
|
|
* Copyright (c) 2005-2008 Nominet UK (www.nic.uk)
|
|
* All rights reserved.
|
|
* Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted
|
|
* their moral rights under the UK Copyright Design and Patents Act 1988 to
|
|
* be recorded as the authors of this copyright work.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
* use this file except in compliance with the License.
|
|
*
|
|
* You may obtain a copy of the License at
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
*
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
/** \file
|
|
*/
|
|
|
|
#include <openssl/md5.h>
|
|
#include <openssl/sha.h>
|
|
#include <openssl/dsa.h>
|
|
#include <openssl/rsa.h>
|
|
#include <openssl/err.h>
|
|
#include <assert.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <openpgpsdk/configure.h>
|
|
#include <openpgpsdk/crypto.h>
|
|
#include <openpgpsdk/keyring.h>
|
|
#include <openpgpsdk/readerwriter.h>
|
|
#include "keyring_local.h"
|
|
#include <openpgpsdk/std_print.h>
|
|
|
|
#include <openpgpsdk/final.h>
|
|
|
|
static int debug=0;
|
|
|
|
void test_secret_key(const ops_secret_key_t *skey)
|
|
{
|
|
RSA* test=RSA_new();
|
|
|
|
test->n=BN_dup(skey->public_key.key.rsa.n);
|
|
test->e=BN_dup(skey->public_key.key.rsa.e);
|
|
|
|
test->d=BN_dup(skey->key.rsa.d);
|
|
test->p=BN_dup(skey->key.rsa.p);
|
|
test->q=BN_dup(skey->key.rsa.q);
|
|
|
|
assert(RSA_check_key(test)==1);
|
|
RSA_free(test);
|
|
}
|
|
|
|
static void md5_init(ops_hash_t *hash)
|
|
{
|
|
assert(!hash->data);
|
|
hash->data=malloc(sizeof(MD5_CTX));
|
|
MD5_Init(hash->data);
|
|
}
|
|
|
|
static void md5_add(ops_hash_t *hash,const unsigned char *data,unsigned length)
|
|
{
|
|
MD5_Update(hash->data,data,length);
|
|
}
|
|
|
|
static unsigned md5_finish(ops_hash_t *hash,unsigned char *out)
|
|
{
|
|
MD5_Final(out,hash->data);
|
|
free(hash->data);
|
|
hash->data=NULL;
|
|
return 16;
|
|
}
|
|
|
|
static ops_hash_t md5={OPS_HASH_MD5,MD5_DIGEST_LENGTH,"MD5",md5_init,md5_add,
|
|
md5_finish,NULL};
|
|
|
|
/**
|
|
\ingroup Core_Crypto
|
|
\brief Initialise to MD5
|
|
\param hash Hash to initialise
|
|
*/
|
|
void ops_hash_md5(ops_hash_t *hash)
|
|
{
|
|
*hash=md5;
|
|
}
|
|
|
|
static void sha1_init(ops_hash_t *hash)
|
|
{
|
|
if (debug)
|
|
{
|
|
fprintf(stderr,"***\n***\nsha1_init\n***\n");
|
|
}
|
|
assert(!hash->data);
|
|
hash->data=malloc(sizeof(SHA_CTX));
|
|
SHA1_Init(hash->data);
|
|
}
|
|
|
|
static void sha1_add(ops_hash_t *hash,const unsigned char *data,
|
|
unsigned length)
|
|
{
|
|
if (debug)
|
|
{
|
|
unsigned int i=0;
|
|
fprintf(stderr,"adding %d to hash:\n ", length);
|
|
for (i=0; i<length; i++)
|
|
{
|
|
fprintf(stderr,"0x%02x ", data[i]);
|
|
if (!((i+1) % 16))
|
|
fprintf(stderr,"\n");
|
|
else if (!((i+1) % 8))
|
|
fprintf(stderr," ");
|
|
}
|
|
fprintf(stderr,"\n");
|
|
}
|
|
SHA1_Update(hash->data,data,length);
|
|
}
|
|
|
|
static unsigned sha1_finish(ops_hash_t *hash,unsigned char *out)
|
|
{
|
|
SHA1_Final(out,hash->data);
|
|
if (debug)
|
|
{
|
|
unsigned i=0;
|
|
fprintf(stderr,"***\n***\nsha1_finish\n***\n");
|
|
for (i=0; i<SHA_DIGEST_LENGTH; i++)
|
|
fprintf(stderr,"0x%02x ",out[i]);
|
|
fprintf(stderr,"\n");
|
|
}
|
|
free(hash->data);
|
|
hash->data=NULL;
|
|
return SHA_DIGEST_LENGTH;
|
|
}
|
|
|
|
static ops_hash_t sha1={OPS_HASH_SHA1,SHA_DIGEST_LENGTH,"SHA1",sha1_init,
|
|
sha1_add,sha1_finish,NULL};
|
|
|
|
/**
|
|
\ingroup Core_Crypto
|
|
\brief Initialise to SHA1
|
|
\param hash Hash to initialise
|
|
*/
|
|
void ops_hash_sha1(ops_hash_t *hash)
|
|
{
|
|
*hash=sha1;
|
|
}
|
|
|
|
static void sha256_init(ops_hash_t *hash)
|
|
{
|
|
if (debug)
|
|
{
|
|
fprintf(stderr,"***\n***\nsha256_init\n***\n");
|
|
}
|
|
assert(!hash->data);
|
|
hash->data=malloc(sizeof(SHA256_CTX));
|
|
SHA256_Init(hash->data);
|
|
}
|
|
|
|
static void sha256_add(ops_hash_t *hash,const unsigned char *data,
|
|
unsigned length)
|
|
{
|
|
if (debug)
|
|
{
|
|
unsigned int i=0;
|
|
fprintf(stderr,"adding %d to hash:\n ", length);
|
|
for (i=0; i<length; i++)
|
|
{
|
|
fprintf(stderr,"0x%02x ", data[i]);
|
|
if (!((i+1) % 16))
|
|
fprintf(stderr,"\n");
|
|
else if (!((i+1) % 8))
|
|
fprintf(stderr," ");
|
|
}
|
|
fprintf(stderr,"\n");
|
|
}
|
|
SHA256_Update(hash->data,data,length);
|
|
}
|
|
|
|
static unsigned sha256_finish(ops_hash_t *hash,unsigned char *out)
|
|
{
|
|
SHA256_Final(out,hash->data);
|
|
if (debug)
|
|
{
|
|
unsigned i=0;
|
|
fprintf(stderr,"***\n***\nsha1_finish\n***\n");
|
|
for (i=0; i<SHA256_DIGEST_LENGTH; i++)
|
|
fprintf(stderr,"0x%02x ",out[i]);
|
|
fprintf(stderr,"\n");
|
|
}
|
|
free(hash->data);
|
|
hash->data=NULL;
|
|
return SHA256_DIGEST_LENGTH;
|
|
}
|
|
|
|
static ops_hash_t sha256={OPS_HASH_SHA256,SHA256_DIGEST_LENGTH,"SHA256",sha256_init,
|
|
sha256_add,sha256_finish,NULL};
|
|
|
|
void ops_hash_sha256(ops_hash_t *hash)
|
|
{
|
|
*hash=sha256;
|
|
}
|
|
|
|
/*
|
|
* SHA384
|
|
*/
|
|
|
|
static void sha384_init(ops_hash_t *hash)
|
|
{
|
|
if (debug)
|
|
{
|
|
fprintf(stderr,"***\n***\nsha384_init\n***\n");
|
|
}
|
|
assert(!hash->data);
|
|
hash->data=malloc(sizeof(SHA512_CTX));
|
|
SHA384_Init(hash->data);
|
|
}
|
|
|
|
static void sha384_add(ops_hash_t *hash,const unsigned char *data,
|
|
unsigned length)
|
|
{
|
|
if (debug)
|
|
{
|
|
unsigned int i=0;
|
|
fprintf(stderr,"adding %d to hash:\n ", length);
|
|
for (i=0; i<length; i++)
|
|
{
|
|
fprintf(stderr,"0x%02x ", data[i]);
|
|
if (!((i+1) % 16))
|
|
fprintf(stderr,"\n");
|
|
else if (!((i+1) % 8))
|
|
fprintf(stderr," ");
|
|
}
|
|
fprintf(stderr,"\n");
|
|
}
|
|
SHA384_Update(hash->data,data,length);
|
|
}
|
|
|
|
static unsigned sha384_finish(ops_hash_t *hash,unsigned char *out)
|
|
{
|
|
SHA384_Final(out,hash->data);
|
|
if (debug)
|
|
{
|
|
unsigned i=0;
|
|
fprintf(stderr,"***\n***\nsha1_finish\n***\n");
|
|
for (i=0; i<SHA384_DIGEST_LENGTH; i++)
|
|
fprintf(stderr,"0x%02x ",out[i]);
|
|
fprintf(stderr,"\n");
|
|
}
|
|
free(hash->data);
|
|
hash->data=NULL;
|
|
return SHA384_DIGEST_LENGTH;
|
|
}
|
|
|
|
static ops_hash_t sha384={OPS_HASH_SHA384,SHA384_DIGEST_LENGTH,"SHA384",sha384_init,
|
|
sha384_add,sha384_finish,NULL};
|
|
|
|
void ops_hash_sha384(ops_hash_t *hash)
|
|
{
|
|
*hash=sha384;
|
|
}
|
|
|
|
/*
|
|
* SHA512
|
|
*/
|
|
|
|
static void sha512_init(ops_hash_t *hash)
|
|
{
|
|
if (debug)
|
|
{
|
|
fprintf(stderr,"***\n***\nsha512_init\n***\n");
|
|
}
|
|
assert(!hash->data);
|
|
hash->data=malloc(sizeof(SHA512_CTX));
|
|
SHA512_Init(hash->data);
|
|
}
|
|
|
|
static void sha512_add(ops_hash_t *hash,const unsigned char *data,
|
|
unsigned length)
|
|
{
|
|
if (debug)
|
|
{
|
|
unsigned int i=0;
|
|
fprintf(stderr,"adding %d to hash:\n ", length);
|
|
for (i=0; i<length; i++)
|
|
{
|
|
fprintf(stderr,"0x%02x ", data[i]);
|
|
if (!((i+1) % 16))
|
|
fprintf(stderr,"\n");
|
|
else if (!((i+1) % 8))
|
|
fprintf(stderr," ");
|
|
}
|
|
fprintf(stderr,"\n");
|
|
}
|
|
SHA512_Update(hash->data,data,length);
|
|
}
|
|
|
|
static unsigned sha512_finish(ops_hash_t *hash,unsigned char *out)
|
|
{
|
|
SHA512_Final(out,hash->data);
|
|
if (debug)
|
|
{
|
|
unsigned i=0;
|
|
fprintf(stderr,"***\n***\nsha1_finish\n***\n");
|
|
for (i=0; i<SHA512_DIGEST_LENGTH; i++)
|
|
fprintf(stderr,"0x%02x ",out[i]);
|
|
fprintf(stderr,"\n");
|
|
}
|
|
free(hash->data);
|
|
hash->data=NULL;
|
|
return SHA512_DIGEST_LENGTH;
|
|
}
|
|
|
|
static ops_hash_t sha512={OPS_HASH_SHA512,SHA512_DIGEST_LENGTH,"SHA512",sha512_init,
|
|
sha512_add,sha512_finish,NULL};
|
|
|
|
void ops_hash_sha512(ops_hash_t *hash)
|
|
{
|
|
*hash=sha512;
|
|
}
|
|
|
|
/*
|
|
* SHA224
|
|
*/
|
|
|
|
static void sha224_init(ops_hash_t *hash)
|
|
{
|
|
if (debug)
|
|
{
|
|
fprintf(stderr,"***\n***\nsha1_init\n***\n");
|
|
}
|
|
assert(!hash->data);
|
|
hash->data=malloc(sizeof(SHA256_CTX));
|
|
SHA224_Init(hash->data);
|
|
}
|
|
|
|
static void sha224_add(ops_hash_t *hash,const unsigned char *data,
|
|
unsigned length)
|
|
{
|
|
if (debug)
|
|
{
|
|
unsigned int i=0;
|
|
fprintf(stderr,"adding %d to hash:\n ", length);
|
|
for (i=0; i<length; i++)
|
|
{
|
|
fprintf(stderr,"0x%02x ", data[i]);
|
|
if (!((i+1) % 16))
|
|
fprintf(stderr,"\n");
|
|
else if (!((i+1) % 8))
|
|
fprintf(stderr," ");
|
|
}
|
|
fprintf(stderr,"\n");
|
|
}
|
|
SHA224_Update(hash->data,data,length);
|
|
}
|
|
|
|
static unsigned sha224_finish(ops_hash_t *hash,unsigned char *out)
|
|
{
|
|
SHA224_Final(out,hash->data);
|
|
if (debug)
|
|
{
|
|
unsigned i=0;
|
|
fprintf(stderr,"***\n***\nsha1_finish\n***\n");
|
|
for (i=0; i<SHA224_DIGEST_LENGTH; i++)
|
|
fprintf(stderr,"0x%02x ",out[i]);
|
|
fprintf(stderr,"\n");
|
|
}
|
|
free(hash->data);
|
|
hash->data=NULL;
|
|
return SHA224_DIGEST_LENGTH;
|
|
}
|
|
|
|
static ops_hash_t sha224={OPS_HASH_SHA224,SHA224_DIGEST_LENGTH,"SHA224",sha224_init,
|
|
sha224_add,sha224_finish,NULL};
|
|
|
|
void ops_hash_sha224(ops_hash_t *hash)
|
|
{
|
|
*hash=sha224;
|
|
}
|
|
|
|
ops_boolean_t already_said = ops_false ;
|
|
|
|
ops_boolean_t ops_dsa_verify(const unsigned char *hash,size_t hash_length,
|
|
const ops_dsa_signature_t *sig,
|
|
const ops_dsa_public_key_t *dsa)
|
|
{
|
|
DSA_SIG *osig;
|
|
DSA *odsa;
|
|
int ret;
|
|
|
|
osig=DSA_SIG_new();
|
|
osig->r=sig->r;
|
|
osig->s=sig->s;
|
|
|
|
if(BN_num_bits(dsa->q) != 160)
|
|
{
|
|
if(!already_said)
|
|
{
|
|
fprintf(stderr,"(WW) ops_dsa_verify: openssl does only supports 'q' of 160 bits. Current is %d bits.\n",BN_num_bits(dsa->q)) ;
|
|
already_said=ops_true ;
|
|
}
|
|
osig->r=osig->s=NULL;
|
|
DSA_SIG_free(osig);
|
|
return ops_false ;
|
|
}
|
|
|
|
odsa=DSA_new();
|
|
odsa->p=dsa->p;
|
|
odsa->q=dsa->q;
|
|
odsa->g=dsa->g;
|
|
odsa->pub_key=dsa->y;
|
|
|
|
if (debug)
|
|
{
|
|
fprintf(stderr,"hash passed in:\n");
|
|
unsigned i;
|
|
for (i=0; i<hash_length; i++)
|
|
{
|
|
fprintf(stderr,"%02x ", hash[i]);
|
|
}
|
|
fprintf(stderr,"\n");
|
|
}
|
|
//printf("hash_length=%ld\n", hash_length);
|
|
//printf("Q=%d\n", BN_num_bytes(odsa->q));
|
|
unsigned int qlen=BN_num_bytes(odsa->q);
|
|
if (qlen < hash_length)
|
|
hash_length=qlen;
|
|
// ret=DSA_do_verify(hash,hash_length,osig,odsa);
|
|
ret=DSA_do_verify(hash,hash_length,osig,odsa);
|
|
if (debug)
|
|
{
|
|
fprintf(stderr,"ret=%d\n",ret);
|
|
}
|
|
|
|
if(ret < 0)
|
|
{
|
|
ERR_load_crypto_strings() ;
|
|
unsigned long err = 0 ;
|
|
while(err = ERR_get_error())
|
|
fprintf(stderr,"DSA_do_verify(): ERR = %ld. lib error:\"%s\", func_error:\"%s\", reason:\"%s\"\n",err,ERR_lib_error_string(err),ERR_func_error_string(err),ERR_reason_error_string(err)) ;
|
|
//assert(ret >= 0);
|
|
return ops_false ;
|
|
}
|
|
|
|
odsa->p=odsa->q=odsa->g=odsa->pub_key=NULL;
|
|
DSA_free(odsa);
|
|
|
|
osig->r=osig->s=NULL;
|
|
DSA_SIG_free(osig);
|
|
|
|
return ret != 0;
|
|
}
|
|
|
|
/**
|
|
\ingroup Core_Crypto
|
|
\brief Recovers message digest from the signature
|
|
\param out Where to write decrypted data to
|
|
\param in Encrypted data
|
|
\param length Length of encrypted data
|
|
\param rsa RSA public key
|
|
\return size of recovered message digest
|
|
*/
|
|
int ops_rsa_public_decrypt(unsigned char *out,const unsigned char *in,
|
|
size_t length,const ops_rsa_public_key_t *rsa)
|
|
{
|
|
RSA *orsa;
|
|
int n;
|
|
|
|
orsa=RSA_new();
|
|
orsa->n=rsa->n;
|
|
orsa->e=rsa->e;
|
|
|
|
n=RSA_public_decrypt(length,in,out,orsa,RSA_NO_PADDING);
|
|
|
|
orsa->n=orsa->e=NULL;
|
|
RSA_free(orsa);
|
|
|
|
return n;
|
|
}
|
|
|
|
/**
|
|
\ingroup Core_Crypto
|
|
\brief Signs data with RSA
|
|
\param out Where to write signature
|
|
\param in Data to sign
|
|
\param length Length of data
|
|
\param srsa RSA secret key
|
|
\param rsa RSA public key
|
|
\return number of bytes decrypted
|
|
*/
|
|
int ops_rsa_private_encrypt(unsigned char *out,const unsigned char *in,
|
|
size_t length,const ops_rsa_secret_key_t *srsa,
|
|
const ops_rsa_public_key_t *rsa)
|
|
{
|
|
RSA *orsa;
|
|
int n;
|
|
|
|
orsa=RSA_new();
|
|
orsa->n=rsa->n; // XXX: do we need n?
|
|
orsa->d=srsa->d;
|
|
orsa->p=srsa->q;
|
|
orsa->q=srsa->p;
|
|
|
|
/* debug */
|
|
orsa->e=rsa->e;
|
|
// If this isn't set, it's very likely that the programmer hasn't
|
|
// decrypted the secret key. RSA_check_key segfaults in that case.
|
|
// Use ops_decrypt_secret_key_from_data() to do that.
|
|
assert(orsa->d);
|
|
assert(RSA_check_key(orsa) == 1);
|
|
orsa->e=NULL;
|
|
/* end debug */
|
|
|
|
n=RSA_private_encrypt(length,in,out,orsa,RSA_NO_PADDING);
|
|
|
|
orsa->n=orsa->d=orsa->p=orsa->q=NULL;
|
|
RSA_free(orsa);
|
|
|
|
return n;
|
|
}
|
|
|
|
/**
|
|
\ingroup Core_Crypto
|
|
\brief Decrypts RSA-encrypted data
|
|
\param out Where to write the plaintext
|
|
\param in Encrypted data
|
|
\param length Length of encrypted data
|
|
\param srsa RSA secret key
|
|
\param rsa RSA public key
|
|
\return size of recovered plaintext
|
|
*/
|
|
int ops_rsa_private_decrypt(unsigned char *out,const unsigned char *in,
|
|
size_t length,const ops_rsa_secret_key_t *srsa,
|
|
const ops_rsa_public_key_t *rsa)
|
|
{
|
|
RSA *orsa;
|
|
int n;
|
|
char errbuf[1024];
|
|
|
|
orsa=RSA_new();
|
|
orsa->n=rsa->n; // XXX: do we need n?
|
|
orsa->d=srsa->d;
|
|
orsa->p=srsa->q;
|
|
orsa->q=srsa->p;
|
|
|
|
/* debug */
|
|
orsa->e=rsa->e;
|
|
assert(RSA_check_key(orsa) == 1);
|
|
orsa->e=NULL;
|
|
/* end debug */
|
|
|
|
n=RSA_private_decrypt(length,in,out,orsa,RSA_NO_PADDING);
|
|
|
|
// printf("ops_rsa_private_decrypt: n=%d\n",n);
|
|
|
|
errbuf[0]='\0';
|
|
if (n==-1)
|
|
{
|
|
unsigned long err=ERR_get_error();
|
|
ERR_error_string(err,&errbuf[0]);
|
|
fprintf(stderr,"openssl error : %s\n",errbuf);
|
|
}
|
|
orsa->n=orsa->d=orsa->p=orsa->q=NULL;
|
|
RSA_free(orsa);
|
|
|
|
return n;
|
|
}
|
|
|
|
/**
|
|
\ingroup Core_Crypto
|
|
\brief RSA-encrypts data
|
|
\param out Where to write the encrypted data
|
|
\param in Plaintext
|
|
\param length Size of plaintext
|
|
\param rsa RSA Public Key
|
|
*/
|
|
int ops_rsa_public_encrypt(unsigned char *out,const unsigned char *in,
|
|
size_t length,const ops_rsa_public_key_t *rsa)
|
|
{
|
|
RSA *orsa;
|
|
int n;
|
|
|
|
// printf("ops_rsa_public_encrypt: length=%ld\n", length);
|
|
|
|
orsa=RSA_new();
|
|
orsa->n=rsa->n;
|
|
orsa->e=rsa->e;
|
|
|
|
// printf("len: %ld\n", length);
|
|
// ops_print_bn("n: ", orsa->n);
|
|
// ops_print_bn("e: ", orsa->e);
|
|
n=RSA_public_encrypt(length,in,out,orsa,RSA_NO_PADDING);
|
|
|
|
if (n==-1)
|
|
{
|
|
BIO *fd_out;
|
|
fd_out=BIO_new_fd(fileno(stderr), BIO_NOCLOSE);
|
|
ERR_print_errors(fd_out);
|
|
}
|
|
|
|
orsa->n=orsa->e=NULL;
|
|
RSA_free(orsa);
|
|
|
|
return n;
|
|
}
|
|
|
|
/**
|
|
\ingroup Core_Crypto
|
|
\brief initialises openssl
|
|
\note Would usually call ops_init() instead
|
|
\sa ops_init()
|
|
*/
|
|
void ops_crypto_init()
|
|
{
|
|
#ifdef DMALLOC
|
|
CRYPTO_malloc_debug_init();
|
|
CRYPTO_dbg_set_options(V_CRYPTO_MDEBUG_ALL);
|
|
CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
\ingroup Core_Crypto
|
|
\brief Finalise openssl
|
|
\note Would usually call ops_finish() instead
|
|
\sa ops_finish()
|
|
*/
|
|
void ops_crypto_finish()
|
|
{
|
|
CRYPTO_cleanup_all_ex_data();
|
|
// FIXME: what should we do instead (function is deprecated)?
|
|
// ERR_remove_state(0);
|
|
#ifdef DMALLOC
|
|
CRYPTO_mem_leaks_fp(stderr);
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
\ingroup Core_Hashes
|
|
\brief Get Hash name
|
|
\param hash Hash struct
|
|
\return Hash name
|
|
*/
|
|
const char *ops_text_from_hash(ops_hash_t *hash)
|
|
{ return hash->name; }
|
|
|
|
/**
|
|
\ingroup HighLevel_KeyGenerate
|
|
\brief Generates an RSA keypair
|
|
\param numbits Modulus size
|
|
\param e Public Exponent
|
|
\param keydata Pointer to keydata struct to hold new key
|
|
\return ops_true if key generated successfully; otherwise ops_false
|
|
\note It is the caller's responsibility to call ops_keydata_free(keydata)
|
|
*/
|
|
ops_boolean_t ops_rsa_generate_keypair(const int numbits, const unsigned long e,
|
|
ops_keydata_t* keydata)
|
|
{
|
|
ops_secret_key_t *skey=NULL;
|
|
RSA *rsa=RSA_new();
|
|
BN_CTX *ctx=BN_CTX_new();
|
|
BIGNUM *ebn=BN_new();
|
|
|
|
ops_keydata_init(keydata,OPS_PTAG_CT_SECRET_KEY);
|
|
skey=ops_get_writable_secret_key_from_data(keydata);
|
|
|
|
// generate the key pair
|
|
|
|
BN_set_word(ebn,e);
|
|
RSA_generate_key_ex(rsa,numbits,ebn,NULL);
|
|
|
|
// populate ops key from ssl key
|
|
|
|
skey->public_key.version=4;
|
|
skey->public_key.creation_time=time(NULL);
|
|
skey->public_key.days_valid=0;
|
|
skey->public_key.algorithm= OPS_PKA_RSA;
|
|
|
|
skey->public_key.key.rsa.n=BN_dup(rsa->n);
|
|
skey->public_key.key.rsa.e=BN_dup(rsa->e);
|
|
|
|
skey->s2k_usage=OPS_S2KU_ENCRYPTED_AND_HASHED;
|
|
skey->s2k_specifier=OPS_S2KS_SALTED;
|
|
//skey->s2k_specifier=OPS_S2KS_SIMPLE;
|
|
skey->algorithm=OPS_SA_CAST5; // \todo make param
|
|
skey->hash_algorithm=OPS_HASH_SHA1; // \todo make param
|
|
skey->octet_count=0;
|
|
skey->checksum=0;
|
|
|
|
skey->key.rsa.d=BN_dup(rsa->d);
|
|
skey->key.rsa.p=BN_dup(rsa->p);
|
|
skey->key.rsa.q=BN_dup(rsa->q);
|
|
skey->key.rsa.u=BN_mod_inverse(NULL,rsa->p, rsa->q, ctx);
|
|
assert(skey->key.rsa.u);
|
|
BN_CTX_free(ctx);
|
|
|
|
RSA_free(rsa);
|
|
|
|
ops_keyid(keydata->key_id, &keydata->key.skey.public_key);
|
|
ops_fingerprint(&keydata->fingerprint, &keydata->key.skey.public_key);
|
|
|
|
// Generate checksum
|
|
|
|
ops_create_info_t *cinfo=NULL;
|
|
ops_memory_t *mem=NULL;
|
|
|
|
ops_setup_memory_write(&cinfo, &mem, 128);
|
|
|
|
ops_push_skey_checksum_writer(cinfo, skey);
|
|
|
|
switch(skey->public_key.algorithm)
|
|
{
|
|
// case OPS_PKA_DSA:
|
|
// return ops_write_mpi(key->key.dsa.x,info);
|
|
|
|
case OPS_PKA_RSA:
|
|
case OPS_PKA_RSA_ENCRYPT_ONLY:
|
|
case OPS_PKA_RSA_SIGN_ONLY:
|
|
if(!ops_write_mpi(skey->key.rsa.d,cinfo)
|
|
|| !ops_write_mpi(skey->key.rsa.p,cinfo)
|
|
|| !ops_write_mpi(skey->key.rsa.q,cinfo)
|
|
|| !ops_write_mpi(skey->key.rsa.u,cinfo))
|
|
return ops_false;
|
|
break;
|
|
|
|
// case OPS_PKA_ELGAMAL:
|
|
// return ops_write_mpi(key->key.elgamal.x,info);
|
|
|
|
default:
|
|
assert(0);
|
|
break;
|
|
}
|
|
|
|
// close rather than pop, since its the only one on the stack
|
|
ops_writer_close(cinfo);
|
|
ops_teardown_memory_write(cinfo, mem);
|
|
|
|
// should now have checksum in skey struct
|
|
|
|
// test
|
|
if (debug)
|
|
test_secret_key(skey);
|
|
|
|
return ops_true;
|
|
}
|
|
|
|
/**
|
|
\ingroup HighLevel_KeyGenerate
|
|
\brief Creates a self-signed RSA keypair
|
|
\param numbits Modulus size
|
|
\param e Public Exponent
|
|
\param userid User ID
|
|
\return The new keypair or NULL
|
|
|
|
\note It is the caller's responsibility to call ops_keydata_free(keydata)
|
|
\sa ops_rsa_generate_keypair()
|
|
\sa ops_keydata_free()
|
|
*/
|
|
ops_keydata_t* ops_rsa_create_selfsigned_keypair(const int numbits, const unsigned long e, ops_user_id_t * userid)
|
|
{
|
|
ops_keydata_t *keydata=NULL;
|
|
|
|
keydata=ops_keydata_new();
|
|
|
|
if (ops_rsa_generate_keypair(numbits, e, keydata) != ops_true
|
|
|| ops_add_selfsigned_userid_to_keydata(keydata, userid) != ops_true)
|
|
{
|
|
ops_keydata_free(keydata);
|
|
return NULL;
|
|
}
|
|
|
|
return keydata;
|
|
}
|
|
|
|
/*
|
|
int ops_dsa_size(const ops_dsa_public_key_t *dsa)
|
|
{
|
|
int size;
|
|
DSA *odsa;
|
|
odsa=DSA_new();
|
|
odsa->p=dsa->p;
|
|
odsa->q=dsa->q;
|
|
odsa->g=dsa->g;
|
|
odsa->pub_key=dsa->y;
|
|
|
|
DSAparams_print_fp(stderr, odsa);
|
|
size=DSA_size(odsa);
|
|
|
|
odsa->p=odsa->q=odsa->g=odsa->pub_key=odsa->priv_key=NULL;
|
|
DSA_free(odsa);
|
|
|
|
return size;
|
|
}
|
|
*/
|
|
|
|
DSA_SIG* ops_dsa_sign(unsigned char* hashbuf, unsigned hashsize, const ops_dsa_secret_key_t *sdsa, const ops_dsa_public_key_t *dsa)
|
|
{
|
|
DSA *odsa;
|
|
DSA_SIG *dsasig;
|
|
|
|
odsa=DSA_new();
|
|
odsa->p=dsa->p;
|
|
odsa->q=dsa->q;
|
|
odsa->g=dsa->g;
|
|
odsa->pub_key=dsa->y;
|
|
odsa->priv_key=sdsa->x;
|
|
|
|
dsasig=DSA_do_sign(hashbuf,hashsize,odsa);
|
|
|
|
odsa->p=odsa->q=odsa->g=odsa->pub_key=odsa->priv_key=NULL;
|
|
DSA_free(odsa);
|
|
|
|
return dsasig;
|
|
}
|
|
|
|
// eof
|