First cut at GPG encrytion support (decryption and doc update are pending).
git-svn-id: file:///home/mbr/svn/fwknop/trunk@39 510a4753-2344-4c79-9c09-4d669213fbeb
This commit is contained in:
parent
04674071ef
commit
e846cdd44d
14
configure.ac
14
configure.ac
@ -3,11 +3,12 @@ dnl Process thie file with autoconf to produce teh configure script
|
|||||||
AC_PREREQ(2.53)
|
AC_PREREQ(2.53)
|
||||||
|
|
||||||
m4_define(my_package, [fwknop])
|
m4_define(my_package, [fwknop])
|
||||||
m4_define(my_version, [2.0.0-alpha])
|
m4_define(my_version, [1.10.0-alpha])
|
||||||
m4_define(my_bug_email, [dstuart@dstuart.org])
|
m4_define(my_bug_email, [dstuart@dstuart.org])
|
||||||
|
|
||||||
AC_INIT(my_package, my_version, my_bug_email)
|
AC_INIT(my_package, my_version, my_bug_email)
|
||||||
AC_CONFIG_AUX_DIR(config)
|
AC_CONFIG_AUX_DIR(config)
|
||||||
|
|
||||||
AM_INIT_AUTOMAKE(my_package, my_version)
|
AM_INIT_AUTOMAKE(my_package, my_version)
|
||||||
|
|
||||||
dnl AM_MAINTAINER_MODE
|
dnl AM_MAINTAINER_MODE
|
||||||
@ -53,9 +54,20 @@ AC_FUNC_MALLOC
|
|||||||
AC_FUNC_REALLOC
|
AC_FUNC_REALLOC
|
||||||
AC_CHECK_FUNCS([bzero gettimeofday memmove memset strchr strcspn strdup strndup strrchr strspn])
|
AC_CHECK_FUNCS([bzero gettimeofday memmove memset strchr strcspn strdup strndup strrchr strspn])
|
||||||
|
|
||||||
|
# Check for gpgme
|
||||||
|
AM_PATH_GPGME
|
||||||
|
GPGME_SUPPORT="yes"
|
||||||
|
AC_CHECK_LIB(gpgme, gpgme_check_version, , GPGME_SUPPORT="no")
|
||||||
|
|
||||||
AC_CONFIG_FILES([Makefile
|
AC_CONFIG_FILES([Makefile
|
||||||
fko/Makefile
|
fko/Makefile
|
||||||
doc/Makefile
|
doc/Makefile
|
||||||
src/Makefile])
|
src/Makefile])
|
||||||
|
|
||||||
AC_OUTPUT
|
AC_OUTPUT
|
||||||
|
|
||||||
|
echo "
|
||||||
|
libfko v${VERSION} has been configured.
|
||||||
|
|
||||||
|
GPG encryption support: $GPGME_SUPPORT
|
||||||
|
"
|
||||||
|
|||||||
@ -354,7 +354,7 @@ gcc -o foo foo.c -I/opt/fko/include -L/opt/fko/lib -lfko
|
|||||||
@cindex message digest types
|
@cindex message digest types
|
||||||
@cindex default message digest
|
@cindex default message digest
|
||||||
|
|
||||||
The fwknop system employs an message digest hash of the @acronym{SPA}
|
The fwknop system employs a message digest hash of the @acronym{SPA}
|
||||||
data as one of the data fields to act a signature which can be used
|
data as one of the data fields to act a signature which can be used
|
||||||
at the receiving end to verify the data is valid. This provides a means
|
at the receiving end to verify the data is valid. This provides a means
|
||||||
to ensure the data was not modified in-transit. The resulting digest
|
to ensure the data was not modified in-transit. The resulting digest
|
||||||
|
|||||||
@ -7,7 +7,7 @@ libfko_source_files = \
|
|||||||
fko_nat_access.c fko_rand_value.c fko_server_auth.c fko.h fko_limits.h \
|
fko_nat_access.c fko_rand_value.c fko_server_auth.c fko.h fko_limits.h \
|
||||||
fko_timestamp.c fko_types.h fko_user.c fko_util.h md5.c md5.h \
|
fko_timestamp.c fko_types.h fko_user.c fko_util.h md5.c md5.h \
|
||||||
rijndael.c rijndael.h sha1.c sha256.c sha.h strlcat.c \
|
rijndael.c rijndael.h sha1.c sha256.c sha.h strlcat.c \
|
||||||
strlcpy.c fko_state.h fko_context.h
|
strlcpy.c fko_state.h fko_context.h gpgme_funcs.c gpgme_funcs.h
|
||||||
|
|
||||||
libfko_la_SOURCES = $(libfko_source_files)
|
libfko_la_SOURCES = $(libfko_source_files)
|
||||||
libfko_la_LDFLAGS = -version-info 0:1:0
|
libfko_la_LDFLAGS = -version-info 0:1:0
|
||||||
|
|||||||
@ -35,7 +35,7 @@
|
|||||||
/* Get random data.
|
/* Get random data.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
get_random_data(unsigned char *data, int len)
|
get_random_data(unsigned char *data, size_t len)
|
||||||
{
|
{
|
||||||
FILE *rfd;
|
FILE *rfd;
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
@ -64,20 +64,23 @@ get_random_data(unsigned char *data, int len)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Function to generate initial salt and initialization vector (iv).
|
|
||||||
* This is is done to be compatible with the data produced via
|
/*** These are Rijndael-specific functions ***/
|
||||||
|
|
||||||
|
/* Rijndael function to generate initial salt and initialization vector
|
||||||
|
* (iv). This is is done to be compatible with the data produced via
|
||||||
* the Perl Crypt::CBC module's use of Rijndael.
|
* the Perl Crypt::CBC module's use of Rijndael.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
salt_and_iv(RIJNDAEL_context *ctx, const char *pass, unsigned char *data)
|
rij_salt_and_iv(RIJNDAEL_context *ctx, const char *pass, unsigned char *data)
|
||||||
{
|
{
|
||||||
char pw_buf[16];
|
char pw_buf[16];
|
||||||
unsigned char tmp_buf[64]; /* How big does this need to be? */
|
unsigned char tmp_buf[64]; /* How big does this need to be? */
|
||||||
unsigned char kiv_buf[48]; /* Key and IV buffer */
|
unsigned char kiv_buf[48]; /* Key and IV buffer */
|
||||||
unsigned char md5_buf[16]; /* Buffer for computed md5 hash */
|
unsigned char md5_buf[16]; /* Buffer for computed md5 hash */
|
||||||
|
|
||||||
int kiv_len = 0;
|
size_t kiv_len = 0;
|
||||||
int plen = strlen(pass);
|
size_t plen = strlen(pass);
|
||||||
|
|
||||||
/* First make pw 16 bytes (pad with "0" (ascii 0x30)) or truncate.
|
/* First make pw 16 bytes (pad with "0" (ascii 0x30)) or truncate.
|
||||||
* Note: pw_buf was initialized with '0' chars (again, not the value
|
* Note: pw_buf was initialized with '0' chars (again, not the value
|
||||||
@ -144,7 +147,7 @@ rijndael_init(RIJNDAEL_context *ctx, const char *pass, unsigned char *data)
|
|||||||
|
|
||||||
/* Generate the salt and initialization vector.
|
/* Generate the salt and initialization vector.
|
||||||
*/
|
*/
|
||||||
salt_and_iv(ctx, pass, data);
|
rij_salt_and_iv(ctx, pass, data);
|
||||||
|
|
||||||
/* Intialize our rinjdael context.
|
/* Intialize our rinjdael context.
|
||||||
*/
|
*/
|
||||||
@ -154,8 +157,8 @@ rijndael_init(RIJNDAEL_context *ctx, const char *pass, unsigned char *data)
|
|||||||
/* Take a chunk of data, encrypt it in the same way the perl Crypt::CBC
|
/* Take a chunk of data, encrypt it in the same way the perl Crypt::CBC
|
||||||
* module would.
|
* module would.
|
||||||
*/
|
*/
|
||||||
int
|
size_t
|
||||||
fko_encrypt(unsigned char *in, int in_len, const char *pass, unsigned char *out)
|
rij_encrypt(unsigned char *in, size_t in_len, const char *pass, unsigned char *out)
|
||||||
{
|
{
|
||||||
RIJNDAEL_context ctx;
|
RIJNDAEL_context ctx;
|
||||||
unsigned char plaintext[16];
|
unsigned char plaintext[16];
|
||||||
@ -208,8 +211,8 @@ fko_encrypt(unsigned char *in, int in_len, const char *pass, unsigned char *out)
|
|||||||
|
|
||||||
/* Decrypt the given data.
|
/* Decrypt the given data.
|
||||||
*/
|
*/
|
||||||
int
|
size_t
|
||||||
fko_decrypt(unsigned char *in, int in_len, const char *pass, unsigned char *out)
|
rij_decrypt(unsigned char *in, size_t in_len, const char *pass, unsigned char *out)
|
||||||
{
|
{
|
||||||
RIJNDAEL_context ctx;
|
RIJNDAEL_context ctx;
|
||||||
unsigned char plaintext[16];
|
unsigned char plaintext[16];
|
||||||
@ -271,5 +274,9 @@ fko_decrypt(unsigned char *in, int in_len, const char *pass, unsigned char *out)
|
|||||||
return(ondx - out);
|
return(ondx - out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*** These are GPG-specific functions ***/
|
||||||
|
|
||||||
|
//--DSS TODO: Finish me
|
||||||
|
|
||||||
|
|
||||||
/***EOF***/
|
/***EOF***/
|
||||||
|
|||||||
@ -26,6 +26,7 @@
|
|||||||
|
|
||||||
#include "fko_common.h"
|
#include "fko_common.h"
|
||||||
#include "rijndael.h"
|
#include "rijndael.h"
|
||||||
|
#include "gpgme_funcs.h"
|
||||||
|
|
||||||
/* Provide the predicted encrypted data size for given input data based
|
/* Provide the predicted encrypted data size for given input data based
|
||||||
* on a 16-byte block size (for Rijndael implementation,this also accounts
|
* on a 16-byte block size (for Rijndael implementation,this also accounts
|
||||||
@ -33,9 +34,13 @@
|
|||||||
*/
|
*/
|
||||||
#define PREDICT_ENCSIZE(x) (1+(x>>4)+(x&0xf?1:0))<<4
|
#define PREDICT_ENCSIZE(x) (1+(x>>4)+(x&0xf?1:0))<<4
|
||||||
|
|
||||||
int fko_encrypt(uchar *in, int len, const char *key, uchar *out);
|
size_t rij_encrypt(unsigned char *in, size_t len, const char *key, unsigned char *out);
|
||||||
int fko_decrypt(uchar *in, int len, const char *key, uchar *out);
|
size_t rij_decrypt(unsigned char *in, size_t len, const char *key, unsigned char *out);
|
||||||
void hex_dump(uchar *data, int size);
|
|
||||||
|
#if HAVE_LIBGPGME
|
||||||
|
int gpg_encrypt(unsigned char *in, size_t len, const char *signer, const char *recip, unsigned char **out, size_t *out_sz);
|
||||||
|
int gpg_decrypt(unsigned char *in, size_t len, const char *key, unsigned char **out, size_t *out_sz);
|
||||||
|
#endif /* HAVE_LIBGPGME */
|
||||||
|
|
||||||
#endif /* CIPHER_FUNCS_H */
|
#endif /* CIPHER_FUNCS_H */
|
||||||
|
|
||||||
|
|||||||
@ -81,6 +81,8 @@ typedef enum {
|
|||||||
FKO_ERROR_INVALID_SPA_ACCESS_MSG,
|
FKO_ERROR_INVALID_SPA_ACCESS_MSG,
|
||||||
FKO_ERROR_INVALID_SPA_NAT_ACCESS_MSG,
|
FKO_ERROR_INVALID_SPA_NAT_ACCESS_MSG,
|
||||||
FKO_ERROR_INVALID_ENCRYPTION_TYPE,
|
FKO_ERROR_INVALID_ENCRYPTION_TYPE,
|
||||||
|
FKO_ERROR_WRONG_ENCRYPTION_TYPE,
|
||||||
|
FKO_ERROR_MISSING_GPG_KEY_DATA,
|
||||||
FKO_ERROR_DECRYPTION_SIZE_ERROR,
|
FKO_ERROR_DECRYPTION_SIZE_ERROR,
|
||||||
FKO_ERROR_DIGEST_VERIFICATION_FAILED,
|
FKO_ERROR_DIGEST_VERIFICATION_FAILED,
|
||||||
/* Add more errors above this line */
|
/* Add more errors above this line */
|
||||||
@ -147,6 +149,12 @@ short fko_get_spa_encryption_type(fko_ctx_t ctx);
|
|||||||
|
|
||||||
char* fko_version(fko_ctx_t ctx);
|
char* fko_version(fko_ctx_t ctx);
|
||||||
|
|
||||||
|
/* GPG-related functions */
|
||||||
|
int fko_set_gpg_recipient(fko_ctx_t ctx, const char *recip);
|
||||||
|
char* fko_get_gpg_recipient(fko_ctx_t ctx);
|
||||||
|
int fko_set_gpg_signer(fko_ctx_t ctx, const char *signer);
|
||||||
|
char* fko_get_gpg_signer(fko_ctx_t ctx);
|
||||||
|
|
||||||
#endif /* FKO_H */
|
#endif /* FKO_H */
|
||||||
|
|
||||||
/***EOF***/
|
/***EOF***/
|
||||||
|
|||||||
@ -45,7 +45,7 @@ fko_set_spa_client_timeout(fko_ctx_t ctx, int timeout)
|
|||||||
|
|
||||||
ctx->client_timeout = timeout;
|
ctx->client_timeout = timeout;
|
||||||
|
|
||||||
ctx->state |= FKO_CLIENT_TIMEOUT_MODIFIED;
|
ctx->state |= FKO_DATA_MODIFIED;
|
||||||
|
|
||||||
/* If a timeout is set, then we may need to verify/change message
|
/* If a timeout is set, then we may need to verify/change message
|
||||||
* type accordingly.
|
* type accordingly.
|
||||||
|
|||||||
@ -26,6 +26,8 @@
|
|||||||
#ifndef FKO_CONTEXT_H
|
#ifndef FKO_CONTEXT_H
|
||||||
#define FKO_CONTEXT_H 1
|
#define FKO_CONTEXT_H 1
|
||||||
|
|
||||||
|
#include "fko_common.h"
|
||||||
|
|
||||||
/* The pieces we need to make an FKO SPA data packet.
|
/* The pieces we need to make an FKO SPA data packet.
|
||||||
*/
|
*/
|
||||||
struct fko_context {
|
struct fko_context {
|
||||||
@ -54,6 +56,12 @@ struct fko_context {
|
|||||||
/* State info */
|
/* State info */
|
||||||
unsigned short state;
|
unsigned short state;
|
||||||
unsigned char initval;
|
unsigned char initval;
|
||||||
|
|
||||||
|
#if HAVE_LIBGPGME
|
||||||
|
/* For gpgme support */
|
||||||
|
char *gpg_recipient;
|
||||||
|
char *gpg_signer;
|
||||||
|
#endif /* HAVE_LIBGPGME */
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* FKO_CONTEXT_H */
|
#endif /* FKO_CONTEXT_H */
|
||||||
|
|||||||
@ -97,15 +97,15 @@ fko_decode_spa_data(fko_ctx_t ctx)
|
|||||||
switch(ctx->digest_type)
|
switch(ctx->digest_type)
|
||||||
{
|
{
|
||||||
case FKO_DIGEST_MD5:
|
case FKO_DIGEST_MD5:
|
||||||
md5_base64(tbuf, ctx->encoded_msg, strlen(ctx->encoded_msg));
|
md5_base64(tbuf, (unsigned char*)ctx->encoded_msg, strlen(ctx->encoded_msg));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FKO_DIGEST_SHA1:
|
case FKO_DIGEST_SHA1:
|
||||||
sha1_base64(tbuf, ctx->encoded_msg, strlen(ctx->encoded_msg));
|
sha1_base64(tbuf, (unsigned char*)ctx->encoded_msg, strlen(ctx->encoded_msg));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FKO_DIGEST_SHA256:
|
case FKO_DIGEST_SHA256:
|
||||||
sha256_base64(tbuf, ctx->encoded_msg, strlen(ctx->encoded_msg));
|
sha256_base64(tbuf, (unsigned char*)ctx->encoded_msg, strlen(ctx->encoded_msg));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,8 +30,8 @@
|
|||||||
#include "base64.h"
|
#include "base64.h"
|
||||||
#include "digest.h"
|
#include "digest.h"
|
||||||
|
|
||||||
/* A rough way to make enough space for a base64 encoded version of
|
/* Take a given string, base64-encode it and append it to the given
|
||||||
* the given string, encode it, and return it.
|
* buffer.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
append_b64(char* tbuf, char *str)
|
append_b64(char* tbuf, char *str)
|
||||||
@ -63,7 +63,7 @@ int
|
|||||||
fko_encode_spa_data(fko_ctx_t ctx)
|
fko_encode_spa_data(fko_ctx_t ctx)
|
||||||
{
|
{
|
||||||
int res, offset = 0;
|
int res, offset = 0;
|
||||||
char tbuf[FKO_ENCODE_TMP_BUF_SIZE] = {0};
|
char *tbuf;
|
||||||
|
|
||||||
/* Must be initialized
|
/* Must be initialized
|
||||||
*/
|
*/
|
||||||
@ -88,6 +88,12 @@ fko_encode_spa_data(fko_ctx_t ctx)
|
|||||||
return(FKO_ERROR_INCOMPLETE_SPA_DATA);
|
return(FKO_ERROR_INCOMPLETE_SPA_DATA);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Allocate our initial tmp buffer.
|
||||||
|
*/
|
||||||
|
tbuf = calloc(1, FKO_ENCODE_TMP_BUF_SIZE);
|
||||||
|
if(tbuf == NULL)
|
||||||
|
return(FKO_ERROR_MEMORY_ALLOCATION);
|
||||||
|
|
||||||
/* Put it together a piece at a time, starting with the rand val.
|
/* Put it together a piece at a time, starting with the rand val.
|
||||||
*/
|
*/
|
||||||
strcpy(tbuf, ctx->rand_val);
|
strcpy(tbuf, ctx->rand_val);
|
||||||
@ -96,7 +102,10 @@ fko_encode_spa_data(fko_ctx_t ctx)
|
|||||||
*/
|
*/
|
||||||
strlcat(tbuf, ":", FKO_ENCODE_TMP_BUF_SIZE);
|
strlcat(tbuf, ":", FKO_ENCODE_TMP_BUF_SIZE);
|
||||||
if((res = append_b64(tbuf, ctx->username)) != FKO_SUCCESS)
|
if((res = append_b64(tbuf, ctx->username)) != FKO_SUCCESS)
|
||||||
|
{
|
||||||
|
free(tbuf);
|
||||||
return(res);
|
return(res);
|
||||||
|
}
|
||||||
|
|
||||||
/* Add the timestamp.
|
/* Add the timestamp.
|
||||||
*/
|
*/
|
||||||
@ -126,7 +135,10 @@ fko_encode_spa_data(fko_ctx_t ctx)
|
|||||||
/* Add the base64-encoded SPA message.
|
/* Add the base64-encoded SPA message.
|
||||||
*/
|
*/
|
||||||
if((res = append_b64(tbuf, ctx->message)) != FKO_SUCCESS)
|
if((res = append_b64(tbuf, ctx->message)) != FKO_SUCCESS)
|
||||||
|
{
|
||||||
|
free(tbuf);
|
||||||
return(res);
|
return(res);
|
||||||
|
}
|
||||||
|
|
||||||
/* If a nat_access message was given, add it to the SPA
|
/* If a nat_access message was given, add it to the SPA
|
||||||
* message.
|
* message.
|
||||||
@ -135,7 +147,10 @@ fko_encode_spa_data(fko_ctx_t ctx)
|
|||||||
{
|
{
|
||||||
strlcat(tbuf, ":", FKO_ENCODE_TMP_BUF_SIZE);
|
strlcat(tbuf, ":", FKO_ENCODE_TMP_BUF_SIZE);
|
||||||
if((res = append_b64(tbuf, ctx->nat_access)) != FKO_SUCCESS)
|
if((res = append_b64(tbuf, ctx->nat_access)) != FKO_SUCCESS)
|
||||||
return(res);
|
{
|
||||||
|
free(tbuf);
|
||||||
|
return(res);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we have a server_auth field set. Add it here.
|
/* If we have a server_auth field set. Add it here.
|
||||||
@ -145,7 +160,10 @@ fko_encode_spa_data(fko_ctx_t ctx)
|
|||||||
{
|
{
|
||||||
strlcat(tbuf, ":", FKO_ENCODE_TMP_BUF_SIZE);
|
strlcat(tbuf, ":", FKO_ENCODE_TMP_BUF_SIZE);
|
||||||
if((res = append_b64(tbuf, ctx->server_auth)) != FKO_SUCCESS)
|
if((res = append_b64(tbuf, ctx->server_auth)) != FKO_SUCCESS)
|
||||||
return(res);
|
{
|
||||||
|
free(tbuf);
|
||||||
|
return(res);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If a client timeout is specified and we are not dealing with a
|
/* If a client timeout is specified and we are not dealing with a
|
||||||
@ -167,17 +185,25 @@ fko_encode_spa_data(fko_ctx_t ctx)
|
|||||||
*/
|
*/
|
||||||
ctx->encoded_msg = strdup(tbuf);
|
ctx->encoded_msg = strdup(tbuf);
|
||||||
if(ctx->encoded_msg == NULL)
|
if(ctx->encoded_msg == NULL)
|
||||||
|
{
|
||||||
|
free(tbuf);
|
||||||
return(FKO_ERROR_MEMORY_ALLOCATION);
|
return(FKO_ERROR_MEMORY_ALLOCATION);
|
||||||
|
}
|
||||||
|
|
||||||
/* At this point we can compute the digest for this SPA data.
|
/* At this point we can compute the digest for this SPA data.
|
||||||
*/
|
*/
|
||||||
if((res = fko_set_spa_digest(ctx)) != FKO_SUCCESS)
|
if((res = fko_set_spa_digest(ctx)) != FKO_SUCCESS)
|
||||||
|
{
|
||||||
|
free(tbuf);
|
||||||
return(res);
|
return(res);
|
||||||
|
}
|
||||||
|
|
||||||
/* Here we can clear the modified flags on the SPA data fields.
|
/* Here we can clear the modified flags on the SPA data fields.
|
||||||
*/
|
*/
|
||||||
FKO_CLEAR_SPA_DATA_MODIFIED(ctx);
|
FKO_CLEAR_SPA_DATA_MODIFIED(ctx);
|
||||||
|
|
||||||
|
free(tbuf);
|
||||||
|
|
||||||
return(FKO_SUCCESS);
|
return(FKO_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,8 +212,6 @@ fko_encode_spa_data(fko_ctx_t ctx)
|
|||||||
char*
|
char*
|
||||||
fko_get_encoded_data(fko_ctx_t ctx)
|
fko_get_encoded_data(fko_ctx_t ctx)
|
||||||
{
|
{
|
||||||
int res;
|
|
||||||
|
|
||||||
/* Must be initialized
|
/* Must be initialized
|
||||||
*/
|
*/
|
||||||
if(!CTX_INITIALIZED(ctx))
|
if(!CTX_INITIALIZED(ctx))
|
||||||
|
|||||||
@ -30,6 +30,179 @@
|
|||||||
|
|
||||||
#define B64_RIJNDAEL_SALT "U2FsdGVkX1"
|
#define B64_RIJNDAEL_SALT "U2FsdGVkX1"
|
||||||
|
|
||||||
|
/* Prep and encrypt using Rijndael
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
_rijndael_encrypt(fko_ctx_t ctx, const char *enc_key)
|
||||||
|
{
|
||||||
|
char *plain;
|
||||||
|
char *b64cipher;
|
||||||
|
unsigned char *cipher;
|
||||||
|
int cipher_len;
|
||||||
|
|
||||||
|
/* Make a bucket big enough to hold the enc msg + digest (plaintext)
|
||||||
|
* and populate it appropriately.
|
||||||
|
*/
|
||||||
|
plain = malloc(strlen(ctx->encoded_msg) + strlen(ctx->digest) + 2);
|
||||||
|
if(plain == NULL)
|
||||||
|
return(FKO_ERROR_MEMORY_ALLOCATION);
|
||||||
|
|
||||||
|
sprintf(plain, "%s:%s", ctx->encoded_msg, ctx->digest);
|
||||||
|
|
||||||
|
/* Make a bucket for the encrypted version and populate it.
|
||||||
|
*/
|
||||||
|
cipher = malloc(strlen(plain) + 32); /* Plus padding for salt and Block */
|
||||||
|
if(cipher == NULL)
|
||||||
|
return(FKO_ERROR_MEMORY_ALLOCATION);
|
||||||
|
|
||||||
|
cipher_len = rij_encrypt(
|
||||||
|
(unsigned char*)plain, strlen(plain), (char*)enc_key, cipher
|
||||||
|
);
|
||||||
|
|
||||||
|
/* Now make a bucket for the base64-encoded version and populate it.
|
||||||
|
*/
|
||||||
|
b64cipher = malloc(((cipher_len / 3) * 4) + 8);
|
||||||
|
if(b64cipher == NULL)
|
||||||
|
return(FKO_ERROR_MEMORY_ALLOCATION);
|
||||||
|
|
||||||
|
b64_encode(cipher, b64cipher, cipher_len);
|
||||||
|
strip_b64_eq(b64cipher);
|
||||||
|
|
||||||
|
ctx->encrypted_msg = strdup(b64cipher);
|
||||||
|
|
||||||
|
/* Clean-up
|
||||||
|
*/
|
||||||
|
free(plain);
|
||||||
|
free(cipher);
|
||||||
|
free(b64cipher);
|
||||||
|
|
||||||
|
if(ctx->encrypted_msg == NULL)
|
||||||
|
return(FKO_ERROR_MEMORY_ALLOCATION);
|
||||||
|
|
||||||
|
return(FKO_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Decode, decrypt, and parse SPA data into the context.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
_rijndael_decrypt(fko_ctx_t ctx, const char *dec_key, int b64_len)
|
||||||
|
{
|
||||||
|
char *tbuf;
|
||||||
|
unsigned char *cipher;
|
||||||
|
int cipher_len, pt_len;
|
||||||
|
|
||||||
|
/* Now see if we need to add the "Salted__" string to the front of the
|
||||||
|
* encrypted data.
|
||||||
|
*/
|
||||||
|
if(strncmp(ctx->encrypted_msg, B64_RIJNDAEL_SALT, strlen(B64_RIJNDAEL_SALT)))
|
||||||
|
{
|
||||||
|
/* We need to realloc space for the salt.
|
||||||
|
*/
|
||||||
|
tbuf = realloc(ctx->encrypted_msg, b64_len + 12);
|
||||||
|
if(tbuf == NULL)
|
||||||
|
return(FKO_ERROR_MEMORY_ALLOCATION);
|
||||||
|
|
||||||
|
memmove(tbuf+10, tbuf, b64_len);
|
||||||
|
ctx->encrypted_msg = memcpy(tbuf, B64_RIJNDAEL_SALT, strlen(B64_RIJNDAEL_SALT));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create a bucket for the (base64) decoded encrypted data and get the
|
||||||
|
* raw cipher data.
|
||||||
|
*/
|
||||||
|
cipher = malloc(strlen(ctx->encrypted_msg));
|
||||||
|
if(cipher == NULL)
|
||||||
|
return(FKO_ERROR_MEMORY_ALLOCATION);
|
||||||
|
|
||||||
|
cipher_len = b64_decode(ctx->encrypted_msg, cipher, b64_len);
|
||||||
|
|
||||||
|
/* Create a bucket for the plaintext data and decrypt the message
|
||||||
|
* data into it.
|
||||||
|
*/
|
||||||
|
ctx->encoded_msg = malloc(cipher_len);
|
||||||
|
if(ctx->encoded_msg == NULL)
|
||||||
|
return(FKO_ERROR_MEMORY_ALLOCATION);
|
||||||
|
|
||||||
|
pt_len = rij_decrypt(cipher, cipher_len, dec_key, (unsigned char*)ctx->encoded_msg);
|
||||||
|
|
||||||
|
/* Done with cipher...
|
||||||
|
*/
|
||||||
|
free(cipher);
|
||||||
|
|
||||||
|
/* The length of the decrypted data should be within 16 of the
|
||||||
|
* length of the encrypted version.
|
||||||
|
*/
|
||||||
|
if(pt_len < (cipher_len - 32))
|
||||||
|
return(FKO_ERROR_DECRYPTION_SIZE_ERROR);
|
||||||
|
|
||||||
|
/* Call fko_decode and return the results.
|
||||||
|
*/
|
||||||
|
return(fko_decode_spa_data(ctx));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if HAVE_LIBGPGME
|
||||||
|
|
||||||
|
/* Prep and encrypt using gpgme
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
_gpg_encrypt(fko_ctx_t ctx, const char *enc_key)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
char *plain;
|
||||||
|
char *b64cipher;
|
||||||
|
unsigned char *cipher;
|
||||||
|
size_t cipher_len;
|
||||||
|
|
||||||
|
/* First make sure we have signer and recipient keys set.
|
||||||
|
*/
|
||||||
|
if(ctx->gpg_signer == NULL || ctx->gpg_recipient == NULL)
|
||||||
|
return(FKO_ERROR_MISSING_GPG_KEY_DATA);
|
||||||
|
|
||||||
|
/* Make a bucket big enough to hold the enc msg + digest (plaintext)
|
||||||
|
* and populate it appropriately.
|
||||||
|
*/
|
||||||
|
plain = malloc(strlen(ctx->encoded_msg) + strlen(ctx->digest) + 2);
|
||||||
|
if(plain == NULL)
|
||||||
|
return(FKO_ERROR_MEMORY_ALLOCATION);
|
||||||
|
|
||||||
|
sprintf(plain, "%s:%s", ctx->encoded_msg, ctx->digest);
|
||||||
|
|
||||||
|
res = gpgme_encrypt(
|
||||||
|
(unsigned char*)plain, strlen(plain),
|
||||||
|
ctx->gpg_signer, ctx->gpg_recipient,
|
||||||
|
enc_key, &cipher, &cipher_len
|
||||||
|
);
|
||||||
|
|
||||||
|
/* --DSS XXX: Better parsing of what went wrong would be nice :)
|
||||||
|
*/
|
||||||
|
if(res != FKO_SUCCESS)
|
||||||
|
return(res);
|
||||||
|
|
||||||
|
/* Now make a bucket for the base64-encoded version and populate it.
|
||||||
|
*/
|
||||||
|
b64cipher = malloc(((cipher_len / 3) * 4) + 8);
|
||||||
|
if(b64cipher == NULL)
|
||||||
|
return(FKO_ERROR_MEMORY_ALLOCATION);
|
||||||
|
|
||||||
|
b64_encode(cipher, b64cipher, cipher_len);
|
||||||
|
strip_b64_eq(b64cipher);
|
||||||
|
|
||||||
|
ctx->encrypted_msg = strdup(b64cipher);
|
||||||
|
|
||||||
|
/* Clean-up
|
||||||
|
*/
|
||||||
|
free(plain);
|
||||||
|
free(cipher);
|
||||||
|
free(b64cipher);
|
||||||
|
|
||||||
|
if(ctx->encrypted_msg == NULL)
|
||||||
|
return(FKO_ERROR_MEMORY_ALLOCATION);
|
||||||
|
|
||||||
|
return(FKO_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* HAVE_LIBGPGME */
|
||||||
|
|
||||||
/* Set the SPA encryption type.
|
/* Set the SPA encryption type.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
@ -68,10 +241,7 @@ fko_get_spa_encryption_type(fko_ctx_t ctx)
|
|||||||
int
|
int
|
||||||
fko_encrypt_spa_data(fko_ctx_t ctx, const char *enc_key)
|
fko_encrypt_spa_data(fko_ctx_t ctx, const char *enc_key)
|
||||||
{
|
{
|
||||||
char *plain;
|
int res;
|
||||||
char *b64cipher;
|
|
||||||
unsigned char *cipher;
|
|
||||||
int cipher_len, res;
|
|
||||||
|
|
||||||
/* Must be initialized
|
/* Must be initialized
|
||||||
*/
|
*/
|
||||||
@ -81,7 +251,7 @@ fko_encrypt_spa_data(fko_ctx_t ctx, const char *enc_key)
|
|||||||
/* If there is no encoded data or the SPA data has been modified,
|
/* If there is no encoded data or the SPA data has been modified,
|
||||||
* go ahead and re-encode here.
|
* go ahead and re-encode here.
|
||||||
*/
|
*/
|
||||||
if(ctx->encoded_msg == NULL || FKO_SPA_DATA_MODIFIED(ctx))
|
if(ctx->encoded_msg == NULL || FKO_IS_SPA_DATA_MODIFIED(ctx))
|
||||||
{
|
{
|
||||||
res = fko_encode_spa_data(ctx);
|
res = fko_encode_spa_data(ctx);
|
||||||
|
|
||||||
@ -96,46 +266,20 @@ fko_encrypt_spa_data(fko_ctx_t ctx, const char *enc_key)
|
|||||||
if(strlen(ctx->encoded_msg) < MIN_SPA_ENCODED_MSG_SIZE)
|
if(strlen(ctx->encoded_msg) < MIN_SPA_ENCODED_MSG_SIZE)
|
||||||
return(FKO_ERROR_MISSING_ENCODED_DATA);
|
return(FKO_ERROR_MISSING_ENCODED_DATA);
|
||||||
|
|
||||||
/* Make a bucket big enough to hold the enc msg + digest (plaintext)
|
/* Encrypt according to type and return...
|
||||||
* and populate it appropriately.
|
|
||||||
*/
|
*/
|
||||||
plain = malloc(strlen(ctx->encoded_msg) + strlen(ctx->digest) + 2);
|
if(ctx->encryption_type == FKO_ENCRYPTION_RIJNDAEL)
|
||||||
if(plain == NULL)
|
return(_rijndael_encrypt(ctx, enc_key));
|
||||||
return(FKO_ERROR_MEMORY_ALLOCATION);
|
|
||||||
|
|
||||||
sprintf(plain, "%s:%s", ctx->encoded_msg, ctx->digest);
|
else if(ctx->encryption_type == FKO_ENCRYPTION_GPG)
|
||||||
|
#if HAVE_LIBGPGME
|
||||||
|
return(_gpg_encrypt(ctx, enc_key));
|
||||||
|
#else
|
||||||
|
return(FKO_ERROR_UNSUPPORTED_FEATURE);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Make a bucket for the encrypted version and populate it.
|
else
|
||||||
*/
|
return(FKO_ERROR_INVALID_ENCRYPTION_TYPE);
|
||||||
cipher = malloc(strlen(plain) + 32); /* Plus padding for salt and Block */
|
|
||||||
if(cipher == NULL)
|
|
||||||
return(FKO_ERROR_MEMORY_ALLOCATION);
|
|
||||||
|
|
||||||
cipher_len = fko_encrypt(
|
|
||||||
(unsigned char*)plain, strlen(plain), (char*)enc_key, cipher
|
|
||||||
);
|
|
||||||
|
|
||||||
/* Now make a bucket for the base64-encoded version and populate it.
|
|
||||||
*/
|
|
||||||
b64cipher = malloc(((cipher_len / 3) * 4) + 8);
|
|
||||||
if(b64cipher == NULL)
|
|
||||||
return(FKO_ERROR_MEMORY_ALLOCATION);
|
|
||||||
|
|
||||||
b64_encode(cipher, b64cipher, cipher_len);
|
|
||||||
strip_b64_eq(b64cipher);
|
|
||||||
|
|
||||||
ctx->encrypted_msg = strdup(b64cipher);
|
|
||||||
|
|
||||||
/* Clean-up
|
|
||||||
*/
|
|
||||||
free(plain);
|
|
||||||
free(cipher);
|
|
||||||
free(b64cipher);
|
|
||||||
|
|
||||||
if(ctx->encrypted_msg == NULL)
|
|
||||||
return(FKO_ERROR_MEMORY_ALLOCATION);
|
|
||||||
|
|
||||||
return(FKO_SUCCESS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Decode, decrypt, and parse SPA data into the context.
|
/* Decode, decrypt, and parse SPA data into the context.
|
||||||
@ -143,9 +287,7 @@ fko_encrypt_spa_data(fko_ctx_t ctx, const char *enc_key)
|
|||||||
int
|
int
|
||||||
fko_decrypt_spa_data(fko_ctx_t ctx, const char *dec_key)
|
fko_decrypt_spa_data(fko_ctx_t ctx, const char *dec_key)
|
||||||
{
|
{
|
||||||
char *tbuf;
|
int b64_len;
|
||||||
unsigned char *cipher;
|
|
||||||
int b64_len, cipher_len, pt_len;
|
|
||||||
|
|
||||||
/* First, make sure we have data to work with.
|
/* First, make sure we have data to work with.
|
||||||
*/
|
*/
|
||||||
@ -154,65 +296,116 @@ fko_decrypt_spa_data(fko_ctx_t ctx, const char *dec_key)
|
|||||||
return(FKO_ERROR_INVALID_DATA);
|
return(FKO_ERROR_INVALID_DATA);
|
||||||
|
|
||||||
/* Determine type of encryption used. For know, we are using the
|
/* Determine type of encryption used. For know, we are using the
|
||||||
* size of the message. However, we will want to come up with a
|
* size of the message.
|
||||||
* more reliable method of identification.
|
*
|
||||||
|
* XXX: We will want to come up with a more reliable method of
|
||||||
|
* identifying the encryption type.
|
||||||
*/
|
*/
|
||||||
b64_len = strlen(ctx->encrypted_msg);
|
b64_len = strlen(ctx->encrypted_msg);
|
||||||
|
|
||||||
if(b64_len > MIN_GNUPG_MSG_SIZE)
|
if(b64_len > MIN_GNUPG_MSG_SIZE)
|
||||||
{
|
{
|
||||||
/* TODO: add GPG handling */
|
ctx->encryption_type = FKO_ENCRYPTION_GPG;
|
||||||
/* Since we do not support GPG yet, we will just fall through */
|
#if HAVE_LIBGPGME
|
||||||
|
return(FKO_ERROR_UNSUPPORTED_FEATURE);
|
||||||
|
//return(_gpg_decrypt(ctx, dec_key));
|
||||||
|
#else
|
||||||
|
return(FKO_ERROR_UNSUPPORTED_FEATURE);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
else /* We are assuming the default of Rijndael */
|
||||||
/* Assuming Rijndael */
|
|
||||||
|
|
||||||
/* Now see if we need to add the "Salted__" string to the front of the
|
|
||||||
* encrypted data.
|
|
||||||
*/
|
|
||||||
if(strncmp(ctx->encrypted_msg, B64_RIJNDAEL_SALT, strlen(B64_RIJNDAEL_SALT)))
|
|
||||||
{
|
{
|
||||||
/* We need to realloc space for the salt.
|
ctx->encryption_type = FKO_ENCRYPTION_RIJNDAEL;
|
||||||
*/
|
return(_rijndael_decrypt(ctx, dec_key, b64_len));
|
||||||
tbuf = realloc(ctx->encrypted_msg, b64_len + 12);
|
|
||||||
if(tbuf == NULL)
|
|
||||||
return(FKO_ERROR_MEMORY_ALLOCATION);
|
|
||||||
|
|
||||||
memmove(tbuf+10, tbuf, b64_len);
|
|
||||||
ctx->encrypted_msg = memcpy(tbuf, B64_RIJNDAEL_SALT, strlen(B64_RIJNDAEL_SALT));
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Create a bucket for the (base64) decoded encrypted data and get the
|
/* Set the GPG recipient key name.
|
||||||
* raw cipher data.
|
*/
|
||||||
|
int
|
||||||
|
fko_set_gpg_recipient(fko_ctx_t ctx, const char *recip)
|
||||||
|
{
|
||||||
|
#if HAVE_LIBGPGME
|
||||||
|
/* Must be initialized
|
||||||
*/
|
*/
|
||||||
cipher = malloc(strlen(ctx->encrypted_msg));
|
if(!CTX_INITIALIZED(ctx))
|
||||||
if(cipher == NULL)
|
return(FKO_ERROR_CTX_NOT_INITIALIZED);
|
||||||
return(FKO_ERROR_MEMORY_ALLOCATION);
|
|
||||||
|
|
||||||
cipher_len = b64_decode(ctx->encrypted_msg, cipher, b64_len);
|
|
||||||
|
|
||||||
/* Create a bucket for the plaintext data and decrypt the message
|
if(ctx->encryption_type != FKO_ENCRYPTION_GPG)
|
||||||
* data into it.
|
return(FKO_ERROR_WRONG_ENCRYPTION_TYPE);
|
||||||
*/
|
|
||||||
ctx->encoded_msg = malloc(cipher_len);
|
ctx->gpg_recipient = strdup(recip);
|
||||||
if(ctx->encoded_msg == NULL)
|
if(ctx->gpg_recipient == NULL)
|
||||||
return(FKO_ERROR_MEMORY_ALLOCATION);
|
return(FKO_ERROR_MEMORY_ALLOCATION);
|
||||||
|
|
||||||
pt_len = fko_decrypt(cipher, cipher_len, dec_key, (unsigned char*)ctx->encoded_msg);
|
ctx->state |= FKO_DATA_MODIFIED;
|
||||||
|
|
||||||
/* Done with cipher...
|
|
||||||
*/
|
|
||||||
free(cipher);
|
|
||||||
|
|
||||||
/* The length of the decrypted data should be within 16 of the
|
return(FKO_SUCCESS);
|
||||||
* length of the encrypted version.
|
#else
|
||||||
*/
|
return(FKO_ERROR_UNSUPPORTED_FEATURE);
|
||||||
if(pt_len < (cipher_len - 32))
|
#endif /* HAVE_LIBGPGME */
|
||||||
return(FKO_ERROR_DECRYPTION_SIZE_ERROR);
|
}
|
||||||
|
|
||||||
/* Call fko_decode and return the results.
|
/* Get the GPG recipient key name.
|
||||||
|
*/
|
||||||
|
char*
|
||||||
|
fko_get_gpg_recipient(fko_ctx_t ctx)
|
||||||
|
{
|
||||||
|
#if HAVE_LIBGPGME
|
||||||
|
/* Must be initialized
|
||||||
*/
|
*/
|
||||||
return(fko_decode_spa_data(ctx));
|
if(!CTX_INITIALIZED(ctx))
|
||||||
|
return(NULL);
|
||||||
|
|
||||||
|
return(ctx->gpg_recipient);
|
||||||
|
#else
|
||||||
|
//--DSS we should make this an error
|
||||||
|
return(NULL);
|
||||||
|
#endif /* HAVE_LIBGPGME */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the GPG signer key name.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
fko_set_gpg_signer(fko_ctx_t ctx, const char *signer)
|
||||||
|
{
|
||||||
|
#if HAVE_LIBGPGME
|
||||||
|
/* Must be initialized
|
||||||
|
*/
|
||||||
|
if(!CTX_INITIALIZED(ctx))
|
||||||
|
return(FKO_ERROR_CTX_NOT_INITIALIZED);
|
||||||
|
|
||||||
|
if(ctx->encryption_type != FKO_ENCRYPTION_GPG)
|
||||||
|
return(FKO_ERROR_WRONG_ENCRYPTION_TYPE);
|
||||||
|
|
||||||
|
ctx->gpg_signer = strdup(signer);
|
||||||
|
if(ctx->gpg_signer == NULL)
|
||||||
|
return(FKO_ERROR_MEMORY_ALLOCATION);
|
||||||
|
|
||||||
|
ctx->state |= FKO_DATA_MODIFIED;
|
||||||
|
|
||||||
|
return(FKO_SUCCESS);
|
||||||
|
#else
|
||||||
|
return(FKO_ERROR_UNSUPPORTED_FEATURE);
|
||||||
|
#endif /* HAVE_LIBGPGME */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the GPG signer key name.
|
||||||
|
*/
|
||||||
|
char*
|
||||||
|
fko_get_gpg_signer(fko_ctx_t ctx)
|
||||||
|
{
|
||||||
|
#if HAVE_LIBGPGME
|
||||||
|
/* Must be initialized
|
||||||
|
*/
|
||||||
|
if(!CTX_INITIALIZED(ctx))
|
||||||
|
return(NULL);
|
||||||
|
|
||||||
|
return(ctx->gpg_signer);
|
||||||
|
#else
|
||||||
|
//--DSS we should make this an error
|
||||||
|
return(NULL);
|
||||||
|
#endif /* HAVE_LIBGPGME */
|
||||||
}
|
}
|
||||||
|
|
||||||
/***EOF***/
|
/***EOF***/
|
||||||
|
|||||||
@ -44,6 +44,8 @@ static const char *fko_err_msgs[] = {
|
|||||||
"Invalid SPA access mesage format",
|
"Invalid SPA access mesage format",
|
||||||
"Invalid SPA nat_access mesage format",
|
"Invalid SPA nat_access mesage format",
|
||||||
"Invalid encryption type",
|
"Invalid encryption type",
|
||||||
|
"Wrong or inappropriate encryption type for this operation",
|
||||||
|
"Missing GPG key data (signer or recipient not set)",
|
||||||
"Unexpected or invalid size for decrypted data",
|
"Unexpected or invalid size for decrypted data",
|
||||||
"The computed digest did not match the digest in the spa data",
|
"The computed digest did not match the digest in the spa data",
|
||||||
"Unsupported or unimplemented feature or function",
|
"Unsupported or unimplemented feature or function",
|
||||||
|
|||||||
@ -209,6 +209,14 @@ fko_destroy(fko_ctx_t ctx)
|
|||||||
if(ctx->encrypted_msg != NULL)
|
if(ctx->encrypted_msg != NULL)
|
||||||
free(ctx->encrypted_msg);
|
free(ctx->encrypted_msg);
|
||||||
|
|
||||||
|
#if HAVE_LIBGPGME
|
||||||
|
if(ctx->gpg_recipient != NULL)
|
||||||
|
free(ctx->gpg_recipient);
|
||||||
|
|
||||||
|
if(ctx->gpg_signer != NULL)
|
||||||
|
free(ctx->gpg_signer);
|
||||||
|
|
||||||
|
#endif /* HAVE_LIBGPGME */
|
||||||
bzero(ctx, sizeof(fko_ctx_t));
|
bzero(ctx, sizeof(fko_ctx_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,8 +243,6 @@ fko_version(fko_ctx_t ctx)
|
|||||||
int
|
int
|
||||||
fko_spa_data_final(fko_ctx_t ctx, const char *enc_key)
|
fko_spa_data_final(fko_ctx_t ctx, const char *enc_key)
|
||||||
{
|
{
|
||||||
int res;
|
|
||||||
|
|
||||||
/* Must be initialized
|
/* Must be initialized
|
||||||
*/
|
*/
|
||||||
if(!CTX_INITIALIZED(ctx))
|
if(!CTX_INITIALIZED(ctx))
|
||||||
@ -250,8 +256,6 @@ fko_spa_data_final(fko_ctx_t ctx, const char *enc_key)
|
|||||||
char*
|
char*
|
||||||
fko_get_spa_data(fko_ctx_t ctx)
|
fko_get_spa_data(fko_ctx_t ctx)
|
||||||
{
|
{
|
||||||
int res;
|
|
||||||
|
|
||||||
/* Must be initialized
|
/* Must be initialized
|
||||||
*/
|
*/
|
||||||
if(!CTX_INITIALIZED(ctx))
|
if(!CTX_INITIALIZED(ctx))
|
||||||
|
|||||||
@ -123,7 +123,7 @@ fko_set_spa_message(fko_ctx_t ctx, const char *msg)
|
|||||||
|
|
||||||
ctx->message = strdup(msg);
|
ctx->message = strdup(msg);
|
||||||
|
|
||||||
ctx->state |= FKO_SPA_MSG_MODIFIED;
|
ctx->state |= FKO_DATA_MODIFIED;
|
||||||
|
|
||||||
if(ctx->message == NULL)
|
if(ctx->message == NULL)
|
||||||
return(FKO_ERROR_MEMORY_ALLOCATION);
|
return(FKO_ERROR_MEMORY_ALLOCATION);
|
||||||
|
|||||||
@ -55,7 +55,7 @@ fko_set_spa_nat_access(fko_ctx_t ctx, const char *msg)
|
|||||||
|
|
||||||
ctx->nat_access = strdup(msg);
|
ctx->nat_access = strdup(msg);
|
||||||
|
|
||||||
ctx->state |= FKO_NAT_ACCESS_MODIFIED;
|
ctx->state |= FKO_DATA_MODIFIED;
|
||||||
|
|
||||||
if(ctx->nat_access == NULL)
|
if(ctx->nat_access == NULL)
|
||||||
return(FKO_ERROR_MEMORY_ALLOCATION);
|
return(FKO_ERROR_MEMORY_ALLOCATION);
|
||||||
|
|||||||
@ -61,7 +61,7 @@ fko_set_rand_value(fko_ctx_t ctx, const char *new_val)
|
|||||||
if(ctx->rand_val == NULL)
|
if(ctx->rand_val == NULL)
|
||||||
return(FKO_ERROR_MEMORY_ALLOCATION);
|
return(FKO_ERROR_MEMORY_ALLOCATION);
|
||||||
|
|
||||||
ctx->state |= FKO_RAND_VAL_MODIFIED;
|
ctx->state |= FKO_DATA_MODIFIED;
|
||||||
|
|
||||||
return(FKO_SUCCESS);
|
return(FKO_SUCCESS);
|
||||||
}
|
}
|
||||||
@ -106,7 +106,7 @@ fko_set_rand_value(fko_ctx_t ctx, const char *new_val)
|
|||||||
|
|
||||||
free(tmp_buf);
|
free(tmp_buf);
|
||||||
|
|
||||||
ctx->state |= FKO_RAND_VAL_MODIFIED;
|
ctx->state |= FKO_DATA_MODIFIED;
|
||||||
|
|
||||||
return(FKO_SUCCESS);
|
return(FKO_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -69,7 +69,7 @@ fko_set_spa_server_auth(fko_ctx_t ctx, const char *msg)
|
|||||||
|
|
||||||
ctx->server_auth = strdup(msg);
|
ctx->server_auth = strdup(msg);
|
||||||
|
|
||||||
ctx->state |= FKO_SERVER_AUTH_MODIFIED;
|
ctx->state |= FKO_DATA_MODIFIED;
|
||||||
|
|
||||||
if(ctx->server_auth == NULL)
|
if(ctx->server_auth == NULL)
|
||||||
return(FKO_ERROR_MEMORY_ALLOCATION);
|
return(FKO_ERROR_MEMORY_ALLOCATION);
|
||||||
|
|||||||
@ -30,19 +30,20 @@
|
|||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
FKO_CTX_SET = 1, /* Set when ctx is initialized */
|
FKO_CTX_SET = 1, /* Set when ctx is initialized */
|
||||||
FKO_RAND_VAL_MODIFIED = 1 << 1,
|
FKO_DATA_MODIFIED = 1 << 1,
|
||||||
FKO_USERNAME_MODIFIED = 1 << 2,
|
FKO_STATE_RESERVED_2 = 1 << 2,
|
||||||
FKO_TIMESTAMP_MODIFIED = 1 << 3,
|
STATE_RESERVED_3 = 1 << 3,
|
||||||
FKO_VERSION_MODIFIED = 1 << 4,
|
STATE_RESERVED_4 = 1 << 4,
|
||||||
|
STATE_RESERVED_5 = 1 << 5,
|
||||||
FKO_SPA_MSG_TYPE_MODIFIED = 1 << 6,
|
FKO_SPA_MSG_TYPE_MODIFIED = 1 << 6,
|
||||||
FKO_CTX_SET_2 = 1 << 7, /* Set when ctx is initialized */
|
FKO_CTX_SET_2 = 1 << 7, /* Set when ctx is initialized */
|
||||||
FKO_SPA_MSG_MODIFIED = 1 << 8,
|
STATE_RESERVED_8 = 1 << 8,
|
||||||
FKO_NAT_ACCESS_MODIFIED = 1 << 9,
|
STATE_RESERVED_9 = 1 << 9,
|
||||||
FKO_SERVER_AUTH_MODIFIED = 1 << 10,
|
STATE_RESERVED_10 = 1 << 10,
|
||||||
FKO_CLIENT_TIMEOUT_MODIFIED = 1 << 11,
|
STATE_RESERVED_11 = 1 << 11,
|
||||||
FKO_DIGEST_TYPE_MODIFIED = 1 << 12,
|
FKO_DIGEST_TYPE_MODIFIED = 1 << 12,
|
||||||
FKO_ENCRYPT_TYPE_MODIFIED = 1 << 13,
|
FKO_ENCRYPT_TYPE_MODIFIED = 1 << 13,
|
||||||
FKO_GPG_SUPPORTED = 1 << 14,
|
STATE_RESERVED_14 = 1 << 14,
|
||||||
FKO_BACKWARD_COMPATIBLE = 1 << 15
|
FKO_BACKWARD_COMPATIBLE = 1 << 15
|
||||||
} fko_state_flags_t;
|
} fko_state_flags_t;
|
||||||
|
|
||||||
@ -62,23 +63,20 @@ typedef enum {
|
|||||||
|
|
||||||
/* Consolidate all SPA data modified flags.
|
/* Consolidate all SPA data modified flags.
|
||||||
*/
|
*/
|
||||||
#define FKO_ANY_SPA_DATA_MODIFIED ( \
|
#define FKO_SPA_DATA_MODIFIED ( \
|
||||||
FKO_RAND_VAL_MODIFIED | FKO_USERNAME_MODIFIED | FKO_TIMESTAMP_MODIFIED \
|
FKO_DATA_MODIFIED | FKO_SPA_MSG_TYPE_MODIFIED \
|
||||||
| FKO_VERSION_MODIFIED | FKO_SPA_MSG_TYPE_MODIFIED | FKO_SPA_MSG_MODIFIED \
|
| FKO_DIGEST_TYPE_MODIFIED | FKO_ENCRYPT_TYPE_MODIFIED )
|
||||||
| FKO_NAT_ACCESS_MODIFIED | FKO_SERVER_AUTH_MODIFIED \
|
|
||||||
| FKO_CLIENT_TIMEOUT_MODIFIED | FKO_DIGEST_TYPE_MODIFIED \
|
|
||||||
| FKO_ENCRYPT_TYPE_MODIFIED )
|
|
||||||
|
|
||||||
/* This should return true if any SPA data field has been modifed since the
|
/* This should return true if any SPA data field has been modifed since the
|
||||||
* last encode/encrypt.
|
* last encode/encrypt.
|
||||||
*/
|
*/
|
||||||
#define FKO_SPA_DATA_MODIFIED(ctx) (ctx->state & FKO_ANY_SPA_DATA_MODIFIED)
|
#define FKO_IS_SPA_DATA_MODIFIED(ctx) (ctx->state & FKO_SPA_DATA_MODIFIED)
|
||||||
|
|
||||||
/* Clear all SPA data modified flags. This is normally called after a
|
/* Clear all SPA data modified flags. This is normally called after a
|
||||||
* succesful encode/digest/encryption cycle.
|
* succesful encode/digest/encryption cycle.
|
||||||
*/
|
*/
|
||||||
#define FKO_CLEAR_SPA_DATA_MODIFIED(ctx) \
|
#define FKO_CLEAR_SPA_DATA_MODIFIED(ctx) \
|
||||||
(ctx->state &= (0xffff & ~FKO_ANY_SPA_DATA_MODIFIED))
|
(ctx->state &= (0xffff & ~FKO_SPA_DATA_MODIFIED))
|
||||||
|
|
||||||
/* Macros used for determining ctx initialization state.
|
/* Macros used for determining ctx initialization state.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -52,7 +52,7 @@ fko_set_timestamp(fko_ctx_t ctx, int offset)
|
|||||||
|
|
||||||
ctx->timestamp = ts;
|
ctx->timestamp = ts;
|
||||||
|
|
||||||
ctx->state |= FKO_TIMESTAMP_MODIFIED;
|
ctx->state |= FKO_DATA_MODIFIED;
|
||||||
|
|
||||||
return(FKO_SUCCESS);
|
return(FKO_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -82,7 +82,7 @@ fko_set_username(fko_ctx_t ctx, const char *spoof_user)
|
|||||||
|
|
||||||
ctx->username = strdup(username);
|
ctx->username = strdup(username);
|
||||||
|
|
||||||
ctx->state |= FKO_USERNAME_MODIFIED;
|
ctx->state |= FKO_DATA_MODIFIED;
|
||||||
|
|
||||||
if(ctx->username == NULL)
|
if(ctx->username == NULL)
|
||||||
return(FKO_ERROR_MEMORY_ALLOCATION);
|
return(FKO_ERROR_MEMORY_ALLOCATION);
|
||||||
|
|||||||
287
fko/gpgme_funcs.c
Normal file
287
fko/gpgme_funcs.c
Normal file
@ -0,0 +1,287 @@
|
|||||||
|
/* $Id$
|
||||||
|
*****************************************************************************
|
||||||
|
*
|
||||||
|
* File: gpgme_funcs.c
|
||||||
|
*
|
||||||
|
* Author: Damien S. Stuart
|
||||||
|
*
|
||||||
|
* Purpose: gpgme-related functions for GPG encryptions support in libfko.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2008 Damien Stuart (dstuart@dstuart.org)
|
||||||
|
*
|
||||||
|
* License (GNU Public License):
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||||
|
* USA
|
||||||
|
*
|
||||||
|
*****************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "fko_common.h"
|
||||||
|
|
||||||
|
#if HAVE_LIBGPGME
|
||||||
|
|
||||||
|
#include <gpgme.h>
|
||||||
|
#include "gpgme_funcs.h"
|
||||||
|
|
||||||
|
/* Callback function that supplies the password when gpgme needs it.
|
||||||
|
*/
|
||||||
|
gpgme_error_t
|
||||||
|
get_gpg_pw(
|
||||||
|
void *hook, const char *uid_hint, const char *passphrase_info,
|
||||||
|
int prev_was_bad, int fd)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* We only need to try once as it is fed by the program
|
||||||
|
* (for now --DSS).
|
||||||
|
*/
|
||||||
|
if(prev_was_bad)
|
||||||
|
return(GPG_ERR_CANCELED);
|
||||||
|
|
||||||
|
write(fd, (const char*)hook, strlen((const char*)hook));
|
||||||
|
write(fd, "\n", 1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the key for the designated signer and add it to the main gpgme context.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
set_signer(gpgme_ctx_t ctx, const char *signer)
|
||||||
|
{
|
||||||
|
gpgme_error_t err;
|
||||||
|
gpgme_ctx_t list_ctx;
|
||||||
|
gpgme_key_t key, key2;
|
||||||
|
|
||||||
|
/* Create a gpgme context for the list
|
||||||
|
*/
|
||||||
|
err = gpgme_new(&list_ctx);
|
||||||
|
if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
|
||||||
|
{
|
||||||
|
return(gpg_err_code(err));
|
||||||
|
}
|
||||||
|
|
||||||
|
err = gpgme_op_keylist_start(list_ctx, signer, 1);
|
||||||
|
|
||||||
|
if (!err)
|
||||||
|
err = gpgme_op_keylist_next(list_ctx, &key);
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
gpgme_release(list_ctx);
|
||||||
|
//secret key not found
|
||||||
|
return(gpg_err_code(err));
|
||||||
|
}
|
||||||
|
|
||||||
|
err = gpgme_op_keylist_next(list_ctx, &key2);
|
||||||
|
|
||||||
|
if (!err)
|
||||||
|
{
|
||||||
|
gpgme_key_release(key);
|
||||||
|
gpgme_key_release(key2);
|
||||||
|
gpgme_release(list_ctx);
|
||||||
|
//ambiguous specfication of secret key
|
||||||
|
return(gpg_err_code(err));
|
||||||
|
}
|
||||||
|
|
||||||
|
gpgme_op_keylist_end(list_ctx);
|
||||||
|
gpgme_release(list_ctx);
|
||||||
|
|
||||||
|
gpgme_signers_clear(ctx);
|
||||||
|
|
||||||
|
err = gpgme_signers_add(ctx, key);
|
||||||
|
|
||||||
|
gpgme_key_release(key);
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
//error setting secret key
|
||||||
|
return(gpg_err_code(err));
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
get_recip_key(gpgme_key_t *mykey, const char *recip)
|
||||||
|
{
|
||||||
|
gpgme_error_t err;
|
||||||
|
gpgme_ctx_t list_ctx;
|
||||||
|
gpgme_key_t key, key2;
|
||||||
|
|
||||||
|
/* Create a gpgme context for the list
|
||||||
|
*/
|
||||||
|
err = gpgme_new(&list_ctx);
|
||||||
|
if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
|
||||||
|
{
|
||||||
|
return(gpg_err_code(err));
|
||||||
|
}
|
||||||
|
|
||||||
|
err = gpgme_op_keylist_start(list_ctx, recip, 1);
|
||||||
|
|
||||||
|
/* Grab the first key in the list (we hope it is the only one).
|
||||||
|
*/
|
||||||
|
err = gpgme_op_keylist_next(list_ctx, &key);
|
||||||
|
if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
|
||||||
|
{
|
||||||
|
gpgme_release(list_ctx);
|
||||||
|
return(gpg_err_code(err));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We try to get the next key match. If we do, then the name is
|
||||||
|
* ambiguous, so we return an error.
|
||||||
|
*/
|
||||||
|
err = gpgme_op_keylist_next(list_ctx, &key2);
|
||||||
|
if(gpg_err_code(err) == GPG_ERR_NO_ERROR) /* Note: look for NO error */
|
||||||
|
{
|
||||||
|
gpgme_key_release(key);
|
||||||
|
gpgme_key_release(key2);
|
||||||
|
gpgme_release(list_ctx);
|
||||||
|
//ambiguous specfication of secret key
|
||||||
|
return(gpg_err_code(err));
|
||||||
|
}
|
||||||
|
|
||||||
|
gpgme_op_keylist_end(list_ctx);
|
||||||
|
|
||||||
|
//printf("Got Key:\n%s: %s <%s>\n",
|
||||||
|
// key->subkeys->keyid, key->uids->name, key->uids->email);
|
||||||
|
|
||||||
|
/* Make our key the first entry in the array (just more gpgme funkyness).
|
||||||
|
*/
|
||||||
|
*mykey = key;
|
||||||
|
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The main GPG encryption routine for libfko.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
gpgme_encrypt(
|
||||||
|
unsigned char *indata, size_t in_len, const char *signer, const char *recip,
|
||||||
|
const char *pw, unsigned char **out, size_t *out_len)
|
||||||
|
{
|
||||||
|
char *tmp_buf;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
gpgme_ctx_t gpg_ctx;
|
||||||
|
gpgme_error_t err;
|
||||||
|
gpgme_key_t key[2] = {0};
|
||||||
|
gpgme_data_t data;
|
||||||
|
gpgme_data_t plaintext;
|
||||||
|
|
||||||
|
/* Because the gpgme manual says you should.
|
||||||
|
*/
|
||||||
|
gpgme_check_version(NULL);
|
||||||
|
|
||||||
|
/* Check for OpenPGP support
|
||||||
|
*/
|
||||||
|
err = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
|
||||||
|
if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
|
||||||
|
{
|
||||||
|
/* GPG engine is not available. */
|
||||||
|
return(gpg_err_code(err));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create our gpgme context
|
||||||
|
*/
|
||||||
|
err = gpgme_new(&gpg_ctx);
|
||||||
|
if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
|
||||||
|
{
|
||||||
|
return(gpg_err_code(err));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize the plaintext data (place into gpgme_data object)
|
||||||
|
*/
|
||||||
|
err = gpgme_data_new_from_mem(&plaintext, (char*)indata, in_len, 1);
|
||||||
|
if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
|
||||||
|
{
|
||||||
|
gpgme_release(gpg_ctx);
|
||||||
|
return(gpg_err_code(err));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set protocol
|
||||||
|
*/
|
||||||
|
err = gpgme_set_protocol(gpg_ctx, GPGME_PROTOCOL_OpenPGP);
|
||||||
|
if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
|
||||||
|
{
|
||||||
|
gpgme_release(gpg_ctx);
|
||||||
|
return(gpg_err_code(err));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set ascii-armor off (we will be base64-encoding the encrypted data
|
||||||
|
* ourselves.
|
||||||
|
*/
|
||||||
|
gpgme_set_armor(gpg_ctx, 0);
|
||||||
|
|
||||||
|
/* Get the signer gpg key
|
||||||
|
*/
|
||||||
|
err = set_signer(gpg_ctx, signer);
|
||||||
|
if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
|
||||||
|
{
|
||||||
|
gpgme_release(gpg_ctx);
|
||||||
|
return(gpg_err_code(err));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the recipient gpg key
|
||||||
|
*/
|
||||||
|
err = get_recip_key((gpgme_key_t*)&key, recip);
|
||||||
|
if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
|
||||||
|
{
|
||||||
|
gpgme_release(gpg_ctx);
|
||||||
|
return(gpg_err_code(err));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create the buffer for our encrypted data.
|
||||||
|
*/
|
||||||
|
err = gpgme_data_new(&data);
|
||||||
|
if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
|
||||||
|
{
|
||||||
|
gpgme_release(gpg_ctx);
|
||||||
|
|
||||||
|
return(gpg_err_code(err));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the passphrase callback.
|
||||||
|
*/
|
||||||
|
gpgme_set_passphrase_cb(gpg_ctx, get_gpg_pw, pw);
|
||||||
|
|
||||||
|
err = gpgme_op_encrypt_sign(gpg_ctx, key, GPGME_ENCRYPT_ALWAYS_TRUST, plaintext, data);
|
||||||
|
if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
|
||||||
|
{
|
||||||
|
//fprintf(stderr, "*Ecrypt&Sign Error: %s\n", gpgme_strerror(err));
|
||||||
|
gpgme_release(gpg_ctx);
|
||||||
|
|
||||||
|
return(gpg_err_code(err));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the encrypted data and its length from the gpgme data object.
|
||||||
|
*/
|
||||||
|
tmp_buf = gpgme_data_release_and_get_mem(data, out_len);
|
||||||
|
|
||||||
|
*out = malloc(*out_len); /* Note: this is freed when the context is destroyed */
|
||||||
|
if(*out == NULL)
|
||||||
|
{
|
||||||
|
res = -2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
res = 0;
|
||||||
|
memcpy(*out, tmp_buf, *out_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
gpgme_free(tmp_buf);
|
||||||
|
gpgme_release(gpg_ctx);
|
||||||
|
|
||||||
|
return(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* HAVE_LIBGPGME */
|
||||||
|
|
||||||
|
/***EOF***/
|
||||||
34
fko/gpgme_funcs.h
Normal file
34
fko/gpgme_funcs.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/* $Id$
|
||||||
|
*****************************************************************************
|
||||||
|
*
|
||||||
|
* File: gpgme_funcs.h
|
||||||
|
*
|
||||||
|
* Author: Damien S. Stuart
|
||||||
|
*
|
||||||
|
* Purpose: Header for the fwknop gpgme_funcs.c.
|
||||||
|
*
|
||||||
|
* License (GNU Public License):
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||||
|
* USA
|
||||||
|
*
|
||||||
|
*****************************************************************************
|
||||||
|
*/
|
||||||
|
#ifndef GPGME_FUNCS_H
|
||||||
|
#define GPGME_FUNCS_H 1
|
||||||
|
|
||||||
|
#include "fko_common.h"
|
||||||
|
|
||||||
|
int gpgme_encrypt(unsigned char *in, size_t len, const char *signer, const char *recip, const char *pw, unsigned char **out, size_t *out_len);
|
||||||
|
int gpgme_decrypt(unsigned char *in, size_t len, const char *pw, unsigned char **out, size_t *out_len);
|
||||||
|
|
||||||
|
#endif /* GPGME_FUNCS_H */
|
||||||
|
|
||||||
|
/***EOF***/
|
||||||
Loading…
x
Reference in New Issue
Block a user