mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-02 12:01:32 +01:00
See ChangeLog: Wed Oct 4 13:16:18 CEST 2000 Werner Koch
This commit is contained in:
parent
986d928ce2
commit
9c20f65cbe
2
NEWS
2
NEWS
@ -3,6 +3,8 @@ Noteworthy changes in the current CVS HEAD
|
||||
|
||||
THIS IS A DEVELOPMENT VERSION; see README-alpha
|
||||
|
||||
* Add Rijndael (AES) support.
|
||||
|
||||
* Fixed problems with piping to/from other MS-Windows software
|
||||
|
||||
* Expiration time of the primary key can be changed again.
|
||||
|
7
TODO
7
TODO
@ -7,11 +7,6 @@
|
||||
|
||||
* Use --output for keylistings too.
|
||||
|
||||
* Add to the (EGD) docs that ~/.gnupg/entropy should be a symlink to the
|
||||
real socket.
|
||||
|
||||
* Add a way to generate keys in batch mode with arbitrary parameters.
|
||||
|
||||
* Never allocate packet memory with a m-alloc, but use a specific function.
|
||||
|
||||
* Should we change names like mpi_write in g10/ so that we don't
|
||||
@ -28,8 +23,6 @@
|
||||
|
||||
* Speed up calculation of key validation.
|
||||
|
||||
* print a warning when a revoked/expired _secret_ key is used.
|
||||
|
||||
* --disable-asm should still assemble _udiv_qrnnd when needed
|
||||
|
||||
* Skip RO keyrings when importing a key.
|
||||
|
@ -1,3 +1,7 @@
|
||||
Wed Oct 4 13:16:18 CEST 2000 Werner Koch <wk@openit.de>
|
||||
|
||||
* run-gpg: redirect fgrep output to stderr
|
||||
|
||||
Sat Nov 13 17:44:23 CET 1999 Werner Koch <wk@gnupg.de>
|
||||
|
||||
* genkey1024.test: Does not use --quick-random anymore.
|
||||
|
@ -1,6 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
[ -n "$show_cmds" ] && echo "../g10/gpg --homedir . $*"
|
||||
[ -n "$show_cmds" ] && echo "../g10/gpg --homedir . $*" >&2
|
||||
|
||||
if ../g10/gpg --homedir . $* 2>err.tmp.$$ ; then
|
||||
:
|
||||
@ -10,6 +10,6 @@ else
|
||||
rm err.tmp.$$
|
||||
exit 1
|
||||
fi
|
||||
fgrep -v -f $srcdir/run-gpg.patterns err.tmp.$$
|
||||
fgrep -v -f $srcdir/run-gpg.patterns err.tmp.$$ >&2
|
||||
rm err.tmp.$$
|
||||
|
||||
|
@ -9,3 +9,6 @@ gpg: NOTE: secret key 439F02CA is NOT protected.
|
||||
gpg: WARNING: using insecure random number generator
|
||||
gpg: NOTE: signature key expired
|
||||
NOTE: this is a development version!
|
||||
secret key without public key - skipped
|
||||
gpg: using secondary key CB879DE9 instead of primary key 439F02CA
|
||||
|
||||
|
@ -1,3 +1,17 @@
|
||||
Wed Oct 4 13:16:18 CEST 2000 Werner Koch <wk@openit.de>
|
||||
|
||||
* sha1.c (transform): Use rol() macro. Actually this is not needed
|
||||
for a newer gcc but there are still aoter compilers.
|
||||
|
||||
* rsa.c (test_keys): Use new random function.
|
||||
|
||||
* md.c (gcry_md_setkey): New function to overcome problems with
|
||||
const conflics.
|
||||
(gcry_md_ctl): Pass set key to the new functions.
|
||||
|
||||
* rijndael.c: New.
|
||||
* cipher.c: Add Rijndael support.
|
||||
|
||||
Mon Sep 18 16:35:45 CEST 2000 Werner Koch <wk@openit.de>
|
||||
|
||||
* rndlinux.c (open_device): Loose random device checking.
|
||||
|
@ -36,6 +36,7 @@ libcipher_la_SOURCES = cipher.c \
|
||||
bithelp.h \
|
||||
des.c \
|
||||
des.h \
|
||||
rijndael.c \
|
||||
twofish.c \
|
||||
blowfish.c \
|
||||
blowfish.h \
|
||||
|
@ -33,7 +33,7 @@
|
||||
#include "dynload.h"
|
||||
|
||||
#define MAX_BLOCKSIZE 16
|
||||
#define TABLE_SIZE 10
|
||||
#define TABLE_SIZE 12
|
||||
#define CTX_MAGIC_NORMAL 0x24091964
|
||||
#define CTX_MAGIC_SECURE 0x46919042
|
||||
|
||||
@ -82,11 +82,43 @@ dummy_decrypt_block( void *c, byte *outbuf, byte *inbuf ) { BUG(); }
|
||||
static void
|
||||
setup_cipher_table(void)
|
||||
{
|
||||
|
||||
int i;
|
||||
|
||||
i = 0;
|
||||
cipher_table[i].algo = CIPHER_ALGO_TWOFISH;
|
||||
cipher_table[i].algo = GCRY_CIPHER_RIJNDAEL;
|
||||
cipher_table[i].name = rijndael_get_info( cipher_table[i].algo,
|
||||
&cipher_table[i].keylen,
|
||||
&cipher_table[i].blocksize,
|
||||
&cipher_table[i].contextsize,
|
||||
&cipher_table[i].setkey,
|
||||
&cipher_table[i].encrypt,
|
||||
&cipher_table[i].decrypt );
|
||||
if( !cipher_table[i].name )
|
||||
BUG();
|
||||
i++;
|
||||
cipher_table[i].algo = GCRY_CIPHER_RIJNDAEL192;
|
||||
cipher_table[i].name = rijndael_get_info( cipher_table[i].algo,
|
||||
&cipher_table[i].keylen,
|
||||
&cipher_table[i].blocksize,
|
||||
&cipher_table[i].contextsize,
|
||||
&cipher_table[i].setkey,
|
||||
&cipher_table[i].encrypt,
|
||||
&cipher_table[i].decrypt );
|
||||
if( !cipher_table[i].name )
|
||||
BUG();
|
||||
i++;
|
||||
cipher_table[i].algo = GCRY_CIPHER_RIJNDAEL256;
|
||||
cipher_table[i].name = rijndael_get_info( cipher_table[i].algo,
|
||||
&cipher_table[i].keylen,
|
||||
&cipher_table[i].blocksize,
|
||||
&cipher_table[i].contextsize,
|
||||
&cipher_table[i].setkey,
|
||||
&cipher_table[i].encrypt,
|
||||
&cipher_table[i].decrypt );
|
||||
if( !cipher_table[i].name )
|
||||
BUG();
|
||||
i++;
|
||||
cipher_table[i].algo = GCRY_CIPHER_TWOFISH;
|
||||
cipher_table[i].name = twofish_get_info( cipher_table[i].algo,
|
||||
&cipher_table[i].keylen,
|
||||
&cipher_table[i].blocksize,
|
||||
@ -97,7 +129,7 @@ setup_cipher_table(void)
|
||||
if( !cipher_table[i].name )
|
||||
BUG();
|
||||
i++;
|
||||
cipher_table[i].algo = CIPHER_ALGO_BLOWFISH;
|
||||
cipher_table[i].algo = GCRY_CIPHER_BLOWFISH;
|
||||
cipher_table[i].name = blowfish_get_info( cipher_table[i].algo,
|
||||
&cipher_table[i].keylen,
|
||||
&cipher_table[i].blocksize,
|
||||
@ -108,7 +140,7 @@ setup_cipher_table(void)
|
||||
if( !cipher_table[i].name )
|
||||
BUG();
|
||||
i++;
|
||||
cipher_table[i].algo = CIPHER_ALGO_CAST5;
|
||||
cipher_table[i].algo = GCRY_CIPHER_CAST5;
|
||||
cipher_table[i].name = cast5_get_info( cipher_table[i].algo,
|
||||
&cipher_table[i].keylen,
|
||||
&cipher_table[i].blocksize,
|
||||
@ -119,7 +151,7 @@ setup_cipher_table(void)
|
||||
if( !cipher_table[i].name )
|
||||
BUG();
|
||||
i++;
|
||||
cipher_table[i].algo = CIPHER_ALGO_3DES;
|
||||
cipher_table[i].algo = GCRY_CIPHER_3DES;
|
||||
cipher_table[i].name = des_get_info( cipher_table[i].algo,
|
||||
&cipher_table[i].keylen,
|
||||
&cipher_table[i].blocksize,
|
||||
@ -455,7 +487,7 @@ do_ecb_encrypt( GCRY_CIPHER_HD c, byte *outbuf, const byte *inbuf, unsigned nblo
|
||||
unsigned n;
|
||||
|
||||
for(n=0; n < nblocks; n++ ) {
|
||||
(*c->encrypt)( &c->context.c, outbuf, inbuf );
|
||||
(*c->encrypt)( &c->context.c, outbuf, (byte*)/*arggg*/inbuf );
|
||||
inbuf += c->blocksize;
|
||||
outbuf += c->blocksize;
|
||||
}
|
||||
@ -467,7 +499,7 @@ do_ecb_decrypt( GCRY_CIPHER_HD c, byte *outbuf, const byte *inbuf, unsigned nblo
|
||||
unsigned n;
|
||||
|
||||
for(n=0; n < nblocks; n++ ) {
|
||||
(*c->decrypt)( &c->context.c, outbuf, inbuf );
|
||||
(*c->decrypt)( &c->context.c, outbuf, (byte*)/*arggg*/inbuf );
|
||||
inbuf += c->blocksize;
|
||||
outbuf += c->blocksize;
|
||||
}
|
||||
@ -507,7 +539,7 @@ do_cbc_decrypt( GCRY_CIPHER_HD c, byte *outbuf, const byte *inbuf, unsigned nblo
|
||||
* to save the original ciphertext block. We use lastiv
|
||||
* for this here because it is not used otherwise */
|
||||
memcpy(c->lastiv, inbuf, blocksize );
|
||||
(*c->decrypt)( &c->context.c, outbuf, inbuf );
|
||||
(*c->decrypt)( &c->context.c, outbuf, (char*)/*argggg*/inbuf );
|
||||
for(ivp=c->iv,i=0; i < blocksize; i++ )
|
||||
outbuf[i] ^= *ivp++;
|
||||
memcpy(c->iv, c->lastiv, blocksize );
|
||||
|
19
cipher/md.c
19
cipher/md.c
@ -557,10 +557,7 @@ gcry_md_ctl( GCRY_MD_HD hd, int cmd, byte *buffer, size_t buflen)
|
||||
if( cmd == GCRYCTL_FINALIZE )
|
||||
md_final( hd );
|
||||
else if( cmd == GCRYCTL_SET_KEY ) {
|
||||
if( !(hd->ctx->macpads ) )
|
||||
rc = GCRYERR_CONFLICT;
|
||||
else if ( !(rc = prepare_macpads( hd, buffer, buflen )) )
|
||||
gcry_md_reset( hd );
|
||||
rc = gcry_md_setkey ( hd, buffer, buflen );
|
||||
}
|
||||
else if( cmd == GCRYCTL_START_DUMP ) {
|
||||
md_start_debug( hd, buffer );
|
||||
@ -574,6 +571,20 @@ gcry_md_ctl( GCRY_MD_HD hd, int cmd, byte *buffer, size_t buflen)
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
gcry_md_setkey( GCRY_MD_HD hd, const char *key, size_t keylen )
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if( !(hd->ctx->macpads ) )
|
||||
rc = GCRYERR_CONFLICT;
|
||||
else if ( !(rc = prepare_macpads( hd, key, keylen )) )
|
||||
gcry_md_reset( hd );
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/****************
|
||||
* if ALGO is null get the digest for the used algo (which should be only one)
|
||||
*/
|
||||
|
@ -27,6 +27,8 @@ void random_dump_stats(void);
|
||||
void secure_random_alloc(void);
|
||||
int quick_random_gen( int onoff );
|
||||
int random_is_faked(void);
|
||||
void secure_random_alloc(void);
|
||||
void random_dump_stats(void);
|
||||
byte *get_random_bits( size_t nbits, int level, int secure );
|
||||
void fast_random_poll( void );
|
||||
|
||||
|
@ -67,10 +67,7 @@ test_keys( RSA_secret_key *sk, unsigned nbits )
|
||||
|
||||
pk.n = sk->n;
|
||||
pk.e = sk->e;
|
||||
{ char *p = get_random_bits( nbits, 0, 0 );
|
||||
mpi_set_buffer( test, p, (nbits+7)/8, 0 );
|
||||
g10_free(p);
|
||||
}
|
||||
gcry_mpi_randomize( test, nbits, GCRY_WEAK_RANDOM );
|
||||
|
||||
public( out1, test, &pk );
|
||||
secret( out2, out1, sk );
|
||||
|
@ -108,7 +108,7 @@ transform( SHA1_CONTEXT *hd, byte *data )
|
||||
|
||||
#define M(i) ( tm = x[i&0x0f] ^ x[(i-14)&0x0f] \
|
||||
^ x[(i-8)&0x0f] ^ x[(i-3)&0x0f] \
|
||||
, (x[i&0x0f] = (tm << 1) | (tm >> 31)) )
|
||||
, (x[i&0x0f] = rol(tm, 1)) )
|
||||
|
||||
#define R(a,b,c,d,e,f,k,m) do { e += rol( a, 5 ) \
|
||||
+ f( b, c, d ) \
|
||||
|
@ -68,7 +68,8 @@
|
||||
specified. It is possible to use these functions as MAC functons; therefore
|
||||
the flag <literal/GCRY_MD_FLAG_HMAC/ must be given along with the
|
||||
hash functions. Other MAC algorithms than HMAC are currently not
|
||||
supported. The key for the MAC must be set using the gcry_md_setkey macro.
|
||||
supported. The key for the MAC must be set using
|
||||
the <function>gcry_md_setkey</> function.
|
||||
<function>gcry_md_close</function> releases all resources associated
|
||||
with the context.
|
||||
<function>gcry_md_enable</function> may be used to enable hash
|
||||
@ -194,6 +195,7 @@
|
||||
hash functions into MAC functions. The key may be any string
|
||||
of the speicified length. The type of the MAC is determined
|
||||
by special flags set with the open function.
|
||||
NEW: There is now a function to do this
|
||||
</para>
|
||||
</refentry>
|
||||
|
||||
@ -479,3 +481,6 @@
|
||||
</para>
|
||||
</refentry>
|
||||
|
||||
|
||||
<!-- FIXME: doc gcry_md_setkey */
|
||||
|
||||
|
@ -18,28 +18,238 @@
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
-->
|
||||
|
||||
<!--
|
||||
const char *gcry_check_version( const char *req_version );
|
||||
<refentry>
|
||||
<refnamediv>
|
||||
<refname>gcry_check_version</refname>
|
||||
<refpurpose>get or check the version of libgcrypt</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
int gcry_errno(void);
|
||||
const char *gcry_strerror( int ec );
|
||||
int gcry_control( enum gcry_ctl_cmds, ... );
|
||||
<refsynopsisdiv>
|
||||
<funcsynopsis>
|
||||
<funcsynopsisinfo>
|
||||
#include <gcrypt.h>
|
||||
</funcsynopsisinfo>
|
||||
<funcprototype>
|
||||
<funcdef>const char *<function>gcry_check_version</function></funcdef>
|
||||
<paramdef>const char *<parameter>req_version</parameter></paramdef>
|
||||
</funcprototype>
|
||||
</funcsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1><title>Description</title>
|
||||
<para>
|
||||
<indexterm><primary>gcry_check_version</primary>
|
||||
</indexterm>
|
||||
<function>gcry_check_version</function> checks
|
||||
that the version of the library is at minimum the requested one
|
||||
and return the version string; NULL is returned if the condition is
|
||||
not met. You may pass NULL as reqy_version to simply get the version
|
||||
string back without any checking.
|
||||
</para>
|
||||
</refentry>
|
||||
|
||||
<refentry>
|
||||
<refnamediv>
|
||||
<refname>gcry_errno</refname>
|
||||
<refname>gcry_strerror</refname>
|
||||
<refpurpose>Get the last error</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<funcsynopsis>
|
||||
<funcsynopsisinfo>
|
||||
#include <gcrypt.h>
|
||||
</funcsynopsisinfo>
|
||||
<funcprototype>
|
||||
<funcdef>int <function>gcry_errno</function></funcdef>
|
||||
</funcprototype>
|
||||
<funcprototype>
|
||||
<funcdef>const char *<function>gcry_strerror</function></funcdef>
|
||||
<paramdef>int<parameter>no</parameter></paramdef>
|
||||
</funcprototype>
|
||||
</funcsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1><title>Description</title>
|
||||
<para>
|
||||
<indexterm><primary>gcry_errno</primary></indexterm>
|
||||
<indexterm><primary>gcry_strerror</primary></indexterm>
|
||||
Both function are to be used like there Standard-C
|
||||
counterparts. However <function>gcry_errno</function> is a function
|
||||
and not just a global variable. If -1 is passed to
|
||||
<function>gcry_strerror</>, <function>gcry_errno</> is implictly used.
|
||||
</para>
|
||||
</refentry>
|
||||
|
||||
|
||||
<refentry>
|
||||
<refnamediv>
|
||||
<refname>gcry_control</refname>
|
||||
<refpurpose>Multi purpose control function</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<funcsynopsis>
|
||||
<funcsynopsisinfo>
|
||||
#include <gcrypt.h>
|
||||
</funcsynopsisinfo>
|
||||
<funcprototype>
|
||||
<funcdef>int <function>gcry_control</function></funcdef>
|
||||
<paramdef>enum gcry_ctl_cmds<parameter>cmd</parameter></paramdef>
|
||||
<paramdef><parameter>...</parameter></paramdef>
|
||||
</funcprototype>
|
||||
</funcsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1><title>Description</title>
|
||||
<para>
|
||||
<indexterm><primary>gcry_control</primary></indexterm>
|
||||
This function is used to control various aspects of &libgcrypt;
|
||||
FIXME: Explain all commands here.
|
||||
</para>
|
||||
</refentry>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<refentry>
|
||||
<refnamediv>
|
||||
<refname>gcry_set_allocation_handler</refname>
|
||||
<refname>gcry_set_outofcore_handler</refname>
|
||||
<refpurpose>Use application defined malloc functions</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<funcsynopsis>
|
||||
<funcsynopsisinfo>
|
||||
#include <gcrypt.h>
|
||||
</funcsynopsisinfo>
|
||||
<funcprototype>
|
||||
<funcdef>void <function>gcry_set_allocation_handler</></funcdef>
|
||||
<paramdef>void *(*<parameter>alloc_func</>)(size_t n)</paramdef>
|
||||
<paramdef>void *(*<parameter>alloc_secure_func</>)(size_t n)</paramdef>
|
||||
<paramdef>int (*<parameter>is_secure_func</>)(const void *p)</paramdef>
|
||||
<paramdef>void *(*<parameter>realloc_func</>)(void *p, size_t n)</paramdef>
|
||||
<paramdef>void (*<parameter>free_func</>)(void *p)</paramdef>
|
||||
</funcprototype>
|
||||
<funcprototype>
|
||||
<funcdef>void <function>gcry_set_outofcore_handler</></funcdef>
|
||||
|
||||
<paramdef>int (*<parameter>h</>)( void*, size_t, unsigned int ),
|
||||
void *opaque )</paramdef>
|
||||
</funcprototype>
|
||||
</funcsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1><title>Description</title>
|
||||
<para>
|
||||
<indexterm><primary>gcry_set_allocation_handler</primary></indexterm>
|
||||
<indexterm><primary>gcry_set_outofcore_handler</primary></indexterm>
|
||||
|
||||
FIXME
|
||||
</para>
|
||||
</refentry>
|
||||
|
||||
|
||||
<refentry>
|
||||
<refnamediv>
|
||||
<refname>gcry_set_fatalerror_handler</refname>
|
||||
<refpurpose>change the default fatal error handler</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<funcsynopsis>
|
||||
<funcsynopsisinfo>
|
||||
#include <gcrypt.h>
|
||||
</funcsynopsisinfo>
|
||||
<funcprototype>
|
||||
<funcdef>void <function>gcry_set_fatalerror_handler</></funcdef>
|
||||
<paramdef>void (*<parameter>func</>)(
|
||||
void *, int, const char*)</paramdef>
|
||||
<paramdef>void *<parameter>opaque</></paramdef>
|
||||
</funcprototype>
|
||||
</funcsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1><title>Description</title>
|
||||
<para>
|
||||
<indexterm><primary>gcry_set_fatalerror_handler</primary></indexterm>
|
||||
At certain places the &libgcrypt; may need to call a fatal error fucntion
|
||||
which does terminate the process. To allow an application to do
|
||||
some emergency cleanup, it may register a fatal error handler with
|
||||
the library. This handler is assumed to terminate the application;
|
||||
however if it returns &libgcrypt; will abort anyway.
|
||||
</para>
|
||||
<para>
|
||||
The handler is called with the opaque value registered here, an
|
||||
errorcode from &libgcrypt; and some descriptive text string.
|
||||
</para>
|
||||
</refentry>
|
||||
|
||||
|
||||
<refentry>
|
||||
<refnamediv>
|
||||
<refname>gcry_set_gettext_handler</refname>
|
||||
<refpurpose>Change the default gettext function</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<funcsynopsis>
|
||||
<funcsynopsisinfo>
|
||||
#include <gcrypt.h>
|
||||
</funcsynopsisinfo>
|
||||
<funcprototype>
|
||||
<funcdef>void <function>gcry_set_gettext_handler</></funcdef>
|
||||
<paramdef>const char *(*<parameter>func</>)(const char*)</paramdef>
|
||||
<paramdef>void *<parameter>opaque</></paramdef>
|
||||
</funcprototype>
|
||||
</funcsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1><title>Description</title>
|
||||
<para>
|
||||
<indexterm><primary>gcry_set_log_handler</primary></indexterm>
|
||||
FIXME!!
|
||||
</para>
|
||||
</refentry>
|
||||
|
||||
|
||||
|
||||
|
||||
void gcry_set_allocation_handler( void *(*new_alloc_func)(size_t n),
|
||||
void *(*new_alloc_secure_func)(size_t n),
|
||||
int (*new_is_secure_func)(const void*),
|
||||
void *(*new_realloc_func)(void *p, size_t n),
|
||||
void (*new_free_func)(void*) );
|
||||
void gcry_set_outofcore_handler( int (*h)( void*, size_t, unsigned int ),
|
||||
void *opaque );
|
||||
void gcry_set_fatalerror_handler( void (*fnc)(void*,int, const char*),
|
||||
void *opaque );
|
||||
void gcry_set_gettext_handler( const char *(*f)(const char*) );
|
||||
void gcry_set_log_handler( void (*f)(void*,int, const char*, va_list ),
|
||||
void *opaque );
|
||||
<refentry>
|
||||
<refnamediv>
|
||||
<refname>gcry_set_log_handler</refname>
|
||||
<refpurpose>Change the default logging function</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<funcsynopsis>
|
||||
<funcsynopsisinfo>
|
||||
#include <gcrypt.h>
|
||||
</funcsynopsisinfo>
|
||||
<funcprototype>
|
||||
<funcdef>void <function>gcry_set_log_handler</></funcdef>
|
||||
<paramdef>void (*<parameter>func</>)
|
||||
(void*, int, const char*, va_list)</paramdef>
|
||||
<paramdef>void *<parameter>opaque</></paramdef>
|
||||
</funcprototype>
|
||||
</funcsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1><title>Description</title>
|
||||
<para>
|
||||
<indexterm><primary>gcry_set_log_handler</primary></indexterm>
|
||||
&libgcrypt; has it;s own logging functions. Applications which
|
||||
need to use their own, should provide a log function to &libgcrypt;
|
||||
so that it will use this function instead.
|
||||
|
||||
Fixme: Describe how this is intended to work.
|
||||
</para>
|
||||
</refentry>
|
||||
|
||||
|
||||
void *gcry_malloc( size_t n );
|
||||
void *gcry_calloc( size_t n, size_t m );
|
||||
@ -55,6 +265,53 @@ char *gcry_xstrdup( const char * a);
|
||||
void gcry_free( void *a );
|
||||
int gcry_is_secure( const void *a );
|
||||
|
||||
<refentry>
|
||||
<refnamediv>
|
||||
<refname>gcry_malloc</refname>
|
||||
<refname>gcry_calloc</refname>
|
||||
<refname>gcry_malloc_secure</refname>
|
||||
<refname>gcry_calloc_secure</refname>
|
||||
<refname>gcry_realloc</refname>
|
||||
<refname>gcry_xmalloc</refname>
|
||||
<refname>gcry_xcalloc</refname>
|
||||
<refname>gcry_xmalloc_secure</refname>
|
||||
<refname>gcry_xcalloc_secure</refname>
|
||||
<refname>gcry_xrealloc</refname>
|
||||
<refname>gcry_xstrdup</refname>
|
||||
|
||||
WORk WORK
|
||||
<refname>gcry_malloc</refname>
|
||||
<refname>gcry_malloc</refname>
|
||||
|
||||
<refpurpose>Change the default logging function</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<funcsynopsis>
|
||||
<funcsynopsisinfo>
|
||||
#include <gcrypt.h>
|
||||
</funcsynopsisinfo>
|
||||
<funcprototype>
|
||||
<funcdef>void <function>gcry_set_log_handler</></funcdef>
|
||||
<paramdef>void (*<parameter>func</>)
|
||||
(void*, int, const char*, va_list)</paramdef>
|
||||
<paramdef>void *<parameter>opaque</></paramdef>
|
||||
</funcprototype>
|
||||
</funcsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1><title>Description</title>
|
||||
<para>
|
||||
<indexterm><primary>gcry_set_log_handler</primary></indexterm>
|
||||
&libgcrypt; has it;s own logging functions. Applications which
|
||||
need to use their own, should provide a log function to &libgcrypt;
|
||||
so that it will use this function instead.
|
||||
|
||||
Fixme: Describe how this is intended to work.
|
||||
</para>
|
||||
</refentry>
|
||||
|
||||
|
||||
|
||||
void gcry_randomize( byte *buffer, size_t length,
|
||||
enum gcry_random_level level );
|
||||
@ -65,3 +322,5 @@ void *gcry_random_bytes_secure( size_t nbytes, enum gcry_random_level level );
|
||||
|
||||
-->
|
||||
|
||||
|
||||
|
||||
|
@ -1,3 +1,18 @@
|
||||
Wed Oct 4 13:16:18 CEST 2000 Werner Koch <wk@openit.de>
|
||||
|
||||
* getkey.c (merge_selfsigs_main): Fixed for v3 keys.
|
||||
|
||||
* sign.c (hash_for): New arg to take packet version in account. Changed
|
||||
all callers.
|
||||
(write_one_sig): New. Moved the shared code from sign_file and
|
||||
clearsign_file to here.
|
||||
* skclist.c (build_sk_list): Fixed usage check.
|
||||
* pkclist.c (build_pk_list): Ditto.
|
||||
|
||||
* encode.c (encode_crypt): Removed duplicated stuff by using
|
||||
encrypt_filter as sign.c already did. Removed already disabled
|
||||
comment-packet code.
|
||||
|
||||
Mon Sep 18 16:35:45 CEST 2000 Werner Koch <wk@openit.de>
|
||||
|
||||
* parse-packet.c (dump_sig_subpkt): Dump key flags.
|
||||
|
63
g10/encode.c
63
g10/encode.c
@ -293,18 +293,17 @@ encode_crypt( const char *filename, STRLIST remusr )
|
||||
PKT_plaintext *pt = NULL;
|
||||
int rc = 0;
|
||||
u32 filesize;
|
||||
cipher_filter_context_t cfx;
|
||||
armor_filter_context_t afx;
|
||||
compress_filter_context_t zfx;
|
||||
text_filter_context_t tfx;
|
||||
encrypt_filter_context_t efx;
|
||||
PK_LIST pk_list;
|
||||
int do_compress = opt.compress && !opt.rfc1991;
|
||||
|
||||
|
||||
memset( &cfx, 0, sizeof cfx);
|
||||
memset( &afx, 0, sizeof afx);
|
||||
memset( &zfx, 0, sizeof zfx);
|
||||
memset( &tfx, 0, sizeof tfx);
|
||||
memset( &efx, 0, sizeof efx);
|
||||
init_packet(&pkt);
|
||||
|
||||
if( (rc=build_pk_list( remusr, &pk_list, GCRY_PK_USAGE_ENCR)) )
|
||||
@ -320,44 +319,25 @@ encode_crypt( const char *filename, STRLIST remusr )
|
||||
else if( opt.verbose )
|
||||
log_info(_("reading from `%s'\n"), filename? filename: "[stdin]");
|
||||
|
||||
/* If the user selected textmode, push the text filter onto the input */
|
||||
if( opt.textmode )
|
||||
iobuf_push_filter( inp, text_filter, &tfx );
|
||||
|
||||
/* Now we can create the outputfile */
|
||||
if( (rc = open_outfile( filename, opt.armor? 1:0, &out )) )
|
||||
goto leave;
|
||||
|
||||
|
||||
/* The first thing we have to push on the output stream
|
||||
* is the armor filter */
|
||||
if( opt.armor )
|
||||
iobuf_push_filter( out, armor_filter, &afx );
|
||||
#ifdef ENABLE_COMMENT_PACKETS
|
||||
else {
|
||||
write_comment( out, "#created by GNUPG v" VERSION " ("
|
||||
PRINTABLE_OS_NAME ")");
|
||||
if( opt.comment_string )
|
||||
write_comment( out, opt.comment_string );
|
||||
}
|
||||
#endif
|
||||
/* create a session key */
|
||||
cfx.dek = gcry_xmalloc_secure( sizeof *cfx.dek );
|
||||
if( !opt.def_cipher_algo ) { /* try to get it from the prefs */
|
||||
cfx.dek->algo = select_algo_from_prefs( pk_list, PREFTYPE_SYM );
|
||||
if( cfx.dek->algo == -1 )
|
||||
cfx.dek->algo = DEFAULT_CIPHER_ALGO;
|
||||
}
|
||||
else
|
||||
cfx.dek->algo = opt.def_cipher_algo;
|
||||
make_session_key( cfx.dek );
|
||||
if( DBG_CIPHER )
|
||||
log_hexdump("DEK is: ", cfx.dek->key, cfx.dek->keylen );
|
||||
|
||||
rc = write_pubkey_enc_from_list( pk_list, cfx.dek, out );
|
||||
if( rc )
|
||||
goto leave;
|
||||
|
||||
/* Prepare the plaintext packet */
|
||||
{
|
||||
if (!opt.no_literal) {
|
||||
/* setup the inner packet */
|
||||
if( filename || opt.set_filename ) {
|
||||
char *s = make_basename( opt.set_filename ? opt.set_filename : filename );
|
||||
char *s = make_basename( opt.set_filename ?
|
||||
opt.set_filename : filename );
|
||||
pt = gcry_xmalloc( sizeof *pt + strlen(s) - 1 );
|
||||
pt->namelen = strlen(s);
|
||||
memcpy(pt->name, s, pt->namelen );
|
||||
@ -388,15 +368,18 @@ encode_crypt( const char *filename, STRLIST remusr )
|
||||
pt->buf = inp;
|
||||
pkt.pkttype = PKT_PLAINTEXT;
|
||||
pkt.pkt.plaintext = pt;
|
||||
cfx.datalen = filesize && !do_compress? calc_packet_length( &pkt ) : 0;
|
||||
efx.cfx.datalen = filesize && !do_compress?
|
||||
calc_packet_length( &pkt ) : 0;
|
||||
}
|
||||
else
|
||||
cfx.datalen = filesize && !do_compress ? filesize : 0;
|
||||
efx.cfx.datalen = filesize && !do_compress ? filesize : 0;
|
||||
} /* end preparation of plaintext packet */
|
||||
|
||||
/* register the cipher filter */
|
||||
iobuf_push_filter( out, cipher_filter, &cfx );
|
||||
/* push in the actual encryption filter */
|
||||
efx.pk_list = pk_list;
|
||||
iobuf_push_filter( out, encrypt_filter, &efx );
|
||||
|
||||
/* register the compress filter */
|
||||
/* register the compress filter (so that it is done before encryption) */
|
||||
if( do_compress ) {
|
||||
int compr_algo = select_algo_from_prefs( pk_list, PREFTYPE_COMPR );
|
||||
if( !compr_algo )
|
||||
@ -414,7 +397,8 @@ encode_crypt( const char *filename, STRLIST remusr )
|
||||
log_error("build_packet failed: %s\n", gpg_errstr(rc) );
|
||||
}
|
||||
else {
|
||||
/* user requested not to create a literal packet, so we copy the plain data */
|
||||
/* user requested not to create a literal packet,
|
||||
* so we copy the plain data */
|
||||
byte copy_buffer[4096];
|
||||
int bytes_copied;
|
||||
while ((bytes_copied = iobuf_read(inp, copy_buffer, 4096)) != -1)
|
||||
@ -423,7 +407,7 @@ encode_crypt( const char *filename, STRLIST remusr )
|
||||
log_error("copying input to output failed: %s\n", gpg_errstr(rc) );
|
||||
break;
|
||||
}
|
||||
memset(copy_buffer, 0, 4096); /* burn buffer */
|
||||
memset(copy_buffer, 0, DIM(copy_buffer)); /* burn buffer */
|
||||
}
|
||||
|
||||
/* finish the stuff */
|
||||
@ -436,7 +420,8 @@ encode_crypt( const char *filename, STRLIST remusr )
|
||||
if( pt )
|
||||
pt->buf = NULL;
|
||||
free_packet(&pkt);
|
||||
gcry_free(cfx.dek);
|
||||
gcry_free(efx.cfx.dek); /* Hmmm, why does the encrypt filter does not
|
||||
* take care about this? */
|
||||
release_pk_list( pk_list );
|
||||
return rc;
|
||||
}
|
||||
@ -445,7 +430,7 @@ encode_crypt( const char *filename, STRLIST remusr )
|
||||
|
||||
|
||||
/****************
|
||||
* Filter to do a complete public key encryption.
|
||||
* Filter to handle the entire public key encryption.
|
||||
*/
|
||||
int
|
||||
encrypt_filter( void *opaque, int control,
|
||||
|
42
g10/getkey.c
42
g10/getkey.c
@ -795,11 +795,18 @@ key_byname( GETKEY_CTX *retctx, STRLIST namelist,
|
||||
ctx->nitems = n;
|
||||
|
||||
for(n=0, r=namelist; r; r = r->next, n++ ) {
|
||||
ctx->items[n].mode = classify_user_id( r->d,
|
||||
int mode = classify_user_id( r->d,
|
||||
ctx->items[n].keyid,
|
||||
ctx->items[n].fprint,
|
||||
&ctx->items[n].name,
|
||||
NULL );
|
||||
|
||||
/* if we don't use one of the exact key specifications, we assume that
|
||||
* the primary key is requested */
|
||||
if ( mode != 10 && mode != 11 && mode != 16 && mode == 20 )
|
||||
ctx->primary = 1;
|
||||
|
||||
ctx->items[n].mode = mode;
|
||||
if( !ctx->items[n].mode ) {
|
||||
gcry_free( ctx );
|
||||
return GPGERR_INV_USER_ID;
|
||||
@ -810,8 +817,7 @@ key_byname( GETKEY_CTX *retctx, STRLIST namelist,
|
||||
}
|
||||
}
|
||||
|
||||
/* and call the lookup function */
|
||||
ctx->primary = 1; /* we want to look for the primary key only */
|
||||
|
||||
|
||||
if ( !ret_kb )
|
||||
ret_kb = &help_kb;
|
||||
@ -1337,8 +1343,13 @@ merge_selfsigs_main( KBNODE keyblock, int *r_revoked )
|
||||
pk->main_keyid[0] = kid[0];
|
||||
pk->main_keyid[1] = kid[1];
|
||||
|
||||
if ( pk->version < 4 )
|
||||
return; /* nothing to do for old keys FIXME: This is wrong!!!!*/
|
||||
if ( pk->version < 4 ) {
|
||||
/* before v4 the key packet itself contains the expiration date
|
||||
* and there was noway to change it. So we also use only the
|
||||
* one from the key packet */
|
||||
key_expire = pk->expiredate;
|
||||
key_expire_seen = 1;
|
||||
}
|
||||
|
||||
/* first pass: find the latest direct key self-signature.
|
||||
* We assume that the newest one overrides all others
|
||||
@ -1394,12 +1405,14 @@ merge_selfsigs_main( KBNODE keyblock, int *r_revoked )
|
||||
key_usage |= GCRY_PK_USAGE_ENCR;
|
||||
}
|
||||
|
||||
p = parse_sig_subpkt ( sig->hashed_data, SIGSUBPKT_KEY_EXPIRE, NULL);
|
||||
if ( pk->version > 3 ) {
|
||||
p = parse_sig_subpkt ( sig->hashed_data,
|
||||
SIGSUBPKT_KEY_EXPIRE, NULL);
|
||||
if ( p ) {
|
||||
key_expire = sig->timestamp + buffer_to_u32(p);
|
||||
key_expire_seen = 1;
|
||||
}
|
||||
|
||||
}
|
||||
/* and set the created field */
|
||||
pk->created = sigdate;
|
||||
/* and mark that key as valid: one direct key signature should
|
||||
@ -1518,8 +1531,8 @@ merge_selfsigs_main( KBNODE keyblock, int *r_revoked )
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( key_expire >= curtime )
|
||||
pk->has_expired = key_expire;
|
||||
|
||||
pk->has_expired = key_expire >= curtime? 0 : key_expire;
|
||||
/* FIXME: we should see how to get rid of the expiretime fields */
|
||||
|
||||
|
||||
@ -1651,7 +1664,7 @@ merge_selfsigs_subkey( KBNODE keyblock, KBNODE subnode )
|
||||
key_expire = sig->timestamp + buffer_to_u32(p);
|
||||
else
|
||||
key_expire = 0;
|
||||
subpk->has_expired = key_expire >= curtime? key_expire : 0;
|
||||
subpk->has_expired = key_expire >= curtime? 0 : key_expire;
|
||||
}
|
||||
|
||||
|
||||
@ -1711,7 +1724,7 @@ merge_selfsigs( KBNODE keyblock )
|
||||
* keys at all and have a way to store just the real secret parts
|
||||
* from the key.
|
||||
*/
|
||||
static void
|
||||
void
|
||||
merge_public_with_secret ( KBNODE pubblock, KBNODE secblock )
|
||||
{
|
||||
KBNODE pub;
|
||||
@ -1942,8 +1955,8 @@ finish_lookup( GETKEY_CTX ctx, KBNODE foundk )
|
||||
}
|
||||
|
||||
if (DBG_CACHE)
|
||||
log_debug( "\tconsidering key created %lu\n",
|
||||
(ulong)pk->created);
|
||||
log_debug( "\tconsidering key %08lX\n",
|
||||
(ulong)keyid_from_pk( pk, NULL));
|
||||
if ( pk->created > latest_date ) {
|
||||
latest_date = pk->created;
|
||||
latest_key = k;
|
||||
@ -1989,7 +2002,8 @@ finish_lookup( GETKEY_CTX ctx, KBNODE foundk )
|
||||
}
|
||||
|
||||
if (DBG_CACHE)
|
||||
log_debug( "\tusing key created %lu\n", (ulong)latest_date );
|
||||
log_debug( "\tusing key %08lX\n",
|
||||
(ulong)keyid_from_pk( latest_key->pkt->pkt.public_key, NULL) );
|
||||
|
||||
ctx->found_key = latest_key;
|
||||
|
||||
|
@ -509,6 +509,10 @@ static void
|
||||
register_extension( const char *mainpgm, const char *fname )
|
||||
{
|
||||
#warning fixme add register cipher extension
|
||||
/* Before we do so, we should design a beter API for this.
|
||||
* I am currently thinking about using S-Exp to pass everything we
|
||||
* need from the module to gcrypt. I hope we are not going to
|
||||
* implement my-own-lisp-library-no-17000 */
|
||||
#if 0
|
||||
if( *fname != '/' ) { /* do tilde expansion etc */
|
||||
char *tmp;
|
||||
|
@ -166,6 +166,7 @@ int get_seckey_next( GETKEY_CTX ctx, PKT_secret_key *sk, KBNODE *ret_keyblock );
|
||||
void get_seckey_end( GETKEY_CTX ctx );
|
||||
int enum_secret_keys( void **context, PKT_secret_key *sk, int with_subkeys );
|
||||
void merge_keys_and_selfsig( KBNODE keyblock );
|
||||
void merge_public_with_secret ( KBNODE pubblock, KBNODE secblock );
|
||||
char*get_user_id_string( u32 *keyid );
|
||||
char*get_user_id_string_native( u32 *keyid );
|
||||
char*get_long_user_id_string( u32 *keyid );
|
||||
|
@ -294,7 +294,6 @@ gen_elg(int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
|
||||
STRING2KEY *s2k, PKT_secret_key **ret_sk, u32 expireval )
|
||||
{
|
||||
int rc;
|
||||
int i;
|
||||
PACKET *pkt;
|
||||
PKT_secret_key *sk;
|
||||
PKT_public_key *pk;
|
||||
@ -407,7 +406,6 @@ gen_dsa(unsigned int nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
|
||||
STRING2KEY *s2k, PKT_secret_key **ret_sk, u32 expireval )
|
||||
{
|
||||
int rc;
|
||||
int i;
|
||||
PACKET *pkt;
|
||||
PKT_secret_key *sk;
|
||||
PKT_public_key *pk;
|
||||
@ -948,7 +946,6 @@ ask_user_id( int mode )
|
||||
|
||||
/* append a warning if we do not have dev/random
|
||||
* or it is switched into quick testmode */
|
||||
#warning quick_random_gen() not available
|
||||
#if 0
|
||||
if( quick_random_gen(-1) )
|
||||
strcpy(p, " (INSECURE!)" );
|
||||
|
@ -454,7 +454,7 @@ fingerprint_from_sk( PKT_secret_key *sk, byte *array, size_t *ret_len )
|
||||
int rc;
|
||||
size_t nbytes;
|
||||
|
||||
#warning Why is the hash sequence for secret keys different
|
||||
/* FIXME: Why is the hash sequence for secret keys different */
|
||||
rc = gcry_mpi_print( GCRYMPI_FMT_USG, NULL, &nbytes, sk->skey[1] );
|
||||
assert( !rc );
|
||||
/* fixme: allocate it on the stack */
|
||||
|
@ -330,6 +330,7 @@ print_cipher_algo_note( int algo )
|
||||
else if( algo == GCRY_CIPHER_3DES
|
||||
|| algo == GCRY_CIPHER_CAST5
|
||||
|| algo == GCRY_CIPHER_BLOWFISH
|
||||
|| algo == GCRY_CIPHER_RIJNDAEL
|
||||
|| algo == GCRY_CIPHER_TWOFISH
|
||||
)
|
||||
;
|
||||
|
@ -819,7 +819,8 @@ build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use )
|
||||
free_public_key( pk ); pk = NULL;
|
||||
log_error(_("%s: skipped: %s\n"), rov->d, gpg_errstr(rc) );
|
||||
}
|
||||
else if( !(rc=openpgp_pk_test_algo(pk->pubkey_algo, use )) ) {
|
||||
else if( !(rc=openpgp_pk_test_algo(pk->pubkey_algo,
|
||||
pk->pubkey_usage)) ) {
|
||||
/* Skip the actual key if the key is already present
|
||||
* in the list */
|
||||
if (key_present_in_pk_list(pk_list, pk) == 0) {
|
||||
@ -874,7 +875,8 @@ build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use )
|
||||
rc = get_pubkey_byname( NULL, pk, answer, NULL );
|
||||
if( rc )
|
||||
tty_printf(_("No such user ID.\n"));
|
||||
else if( !(rc=openpgp_pk_test_algo(pk->pubkey_algo, use)) ) {
|
||||
else if( !(rc=openpgp_pk_test_algo(pk->pubkey_algo,
|
||||
pk->pubkey_usage)) ) {
|
||||
if( have_def_rec ) {
|
||||
if (key_present_in_pk_list(pk_list, pk) == 0) {
|
||||
free_public_key(pk); pk = NULL;
|
||||
@ -940,7 +942,8 @@ build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use )
|
||||
rc = get_pubkey_byname( NULL, pk, def_rec, NULL );
|
||||
if( rc )
|
||||
log_error(_("unknown default recipient `%s'\n"), def_rec );
|
||||
else if( !(rc=openpgp_pk_test_algo(pk->pubkey_algo, use)) ) {
|
||||
else if( !(rc=openpgp_pk_test_algo(pk->pubkey_algo,
|
||||
pk->pubkey_usage)) ) {
|
||||
PK_LIST r = gcry_xmalloc( sizeof *r );
|
||||
r->pk = pk; pk = NULL;
|
||||
r->next = pk_list;
|
||||
@ -966,7 +969,8 @@ build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use )
|
||||
free_public_key( pk ); pk = NULL;
|
||||
log_error(_("%s: skipped: %s\n"), remusr->d, gpg_errstr(rc) );
|
||||
}
|
||||
else if( !(rc=openpgp_pk_test_algo(pk->pubkey_algo, use )) ) {
|
||||
else if( !(rc=openpgp_pk_test_algo(pk->pubkey_algo,
|
||||
pk->pubkey_usage)) ) {
|
||||
int trustlevel;
|
||||
|
||||
rc = check_trust( pk, &trustlevel, pk->namehash, NULL, NULL );
|
||||
|
@ -75,7 +75,6 @@ pk_check_secret_key( int algo, MPI *skey )
|
||||
static int
|
||||
do_check( PKT_secret_key *sk )
|
||||
{
|
||||
byte *buffer;
|
||||
u16 csum=0;
|
||||
int i, res;
|
||||
unsigned nbytes;
|
||||
@ -324,7 +323,7 @@ protect_secret_key( PKT_secret_key *sk, DEK *dek )
|
||||
GCRY_STRONG_RANDOM);
|
||||
gcry_cipher_setiv( cipher_hd, sk->protect.iv, sk->protect.ivlen );
|
||||
|
||||
#warning FIXME: replace set/get buffer
|
||||
/* FIXME: replace set/get buffer */
|
||||
if( sk->version >= 4 ) {
|
||||
byte *bufarr[GNUPG_MAX_NSKEY];
|
||||
unsigned narr[GNUPG_MAX_NSKEY];
|
||||
@ -336,7 +335,7 @@ protect_secret_key( PKT_secret_key *sk, DEK *dek )
|
||||
i < pubkey_get_nskey(sk->pubkey_algo); i++, j++ ) {
|
||||
assert( !gcry_mpi_get_flag( sk->skey[i], GCRYMPI_FLAG_OPAQUE ) );
|
||||
|
||||
if( gcry_mpi_aprint( GCRYMPI_FMT_USG, (char*)bufarr+j,
|
||||
if( gcry_mpi_aprint( GCRYMPI_FMT_USG, (void**)bufarr+j,
|
||||
narr+j, sk->skey[i]))
|
||||
BUG();
|
||||
|
||||
@ -374,7 +373,7 @@ protect_secret_key( PKT_secret_key *sk, DEK *dek )
|
||||
else {
|
||||
/* NOTE: we always recalculate the checksum because there
|
||||
* are some test releases which calculated it wrong */
|
||||
#warning FIXME: Replace this code
|
||||
/* FIXME: Replace this code -- Hmmm: why */
|
||||
csum = 0;
|
||||
for(i=pubkey_get_npkey(sk->pubkey_algo);
|
||||
i < pubkey_get_nskey(sk->pubkey_algo); i++ ) {
|
||||
|
300
g10/sign.c
300
g10/sign.c
@ -40,6 +40,8 @@
|
||||
#include "i18n.h"
|
||||
|
||||
|
||||
#define ENABLE_BETTER_PGP2_COMPAT 1
|
||||
|
||||
#ifdef HAVE_DOSISH_SYSTEM
|
||||
#define LF "\r\n"
|
||||
#else
|
||||
@ -217,13 +219,13 @@ complete_sig( PKT_signature *sig, PKT_secret_key *sk, GCRY_MD_HD md )
|
||||
}
|
||||
|
||||
static int
|
||||
hash_for(int pubkey_algo )
|
||||
hash_for(int pubkey_algo, int packet_version )
|
||||
{
|
||||
if( opt.def_digest_algo )
|
||||
return opt.def_digest_algo;
|
||||
if( pubkey_algo == GCRY_PK_DSA )
|
||||
return GCRY_MD_SHA1;
|
||||
if( pubkey_algo == GCRY_PK_RSA )
|
||||
if( pubkey_algo == GCRY_PK_RSA && packet_version < 4 )
|
||||
return GCRY_MD_MD5;
|
||||
return DEFAULT_DIGEST_ALGO;
|
||||
}
|
||||
@ -265,6 +267,94 @@ print_status_sig_created ( PKT_secret_key *sk, PKT_signature *sig, int what )
|
||||
write_status_text( STATUS_SIG_CREATED, buf );
|
||||
}
|
||||
|
||||
static int
|
||||
write_one_signature( IOBUF out, PKT_secret_key *sk, int old_style,
|
||||
const char *outfile,
|
||||
GCRY_MD_HD datamd,
|
||||
int sig_class,
|
||||
int status_char )
|
||||
{
|
||||
PKT_signature *sig;
|
||||
GCRY_MD_HD md;
|
||||
int rc;
|
||||
|
||||
/* build the signature packet */
|
||||
/* fixme: this code is partly duplicated in make_keysig_packet */
|
||||
sig = gcry_xcalloc( 1, sizeof *sig );
|
||||
sig->version = old_style || opt.force_v3_sigs ? 3 : sk->version;
|
||||
keyid_from_sk( sk, sig->keyid );
|
||||
sig->digest_algo = hash_for(sk->pubkey_algo, sk->version);
|
||||
sig->pubkey_algo = sk->pubkey_algo;
|
||||
sig->timestamp = make_timestamp();
|
||||
sig->sig_class = sig_class;
|
||||
|
||||
md = gcry_md_copy( datamd );
|
||||
if( !md )
|
||||
BUG();
|
||||
if( sig->version >= 4 ) {
|
||||
build_sig_subpkt_from_sig( sig );
|
||||
gcry_md_putc( md, sig->version );
|
||||
}
|
||||
|
||||
mk_notation_and_policy( sig );
|
||||
|
||||
gcry_md_putc( md, sig->sig_class );
|
||||
if( sig->version < 4 ) {
|
||||
u32 a = sig->timestamp;
|
||||
gcry_md_putc( md, (a >> 24) & 0xff );
|
||||
gcry_md_putc( md, (a >> 16) & 0xff );
|
||||
gcry_md_putc( md, (a >> 8) & 0xff );
|
||||
gcry_md_putc( md, a & 0xff );
|
||||
}
|
||||
else {
|
||||
byte buf[6];
|
||||
size_t n;
|
||||
|
||||
gcry_md_putc( md, sig->pubkey_algo );
|
||||
gcry_md_putc( md, sig->digest_algo );
|
||||
if( sig->hashed_data ) {
|
||||
n = (sig->hashed_data[0] << 8) | sig->hashed_data[1];
|
||||
gcry_md_write( md, sig->hashed_data, n+2 );
|
||||
n += 6;
|
||||
}
|
||||
else {
|
||||
gcry_md_putc( md, 0 );/* always hash the length of the subpacket*/
|
||||
gcry_md_putc( md, 0 );
|
||||
n = 6;
|
||||
}
|
||||
/* add some magic */
|
||||
buf[0] = sig->version;
|
||||
buf[1] = 0xff;
|
||||
buf[2] = n >> 24; /* hmmm, n is only 16 bit, so this is always 0 */
|
||||
buf[3] = n >> 16;
|
||||
buf[4] = n >> 8;
|
||||
buf[5] = n;
|
||||
gcry_md_write( md, buf, 6 );
|
||||
}
|
||||
gcry_md_final( md );
|
||||
|
||||
rc = do_sign( sk, sig, md, hash_for(sig->pubkey_algo, sk->version) );
|
||||
gcry_md_close( md );
|
||||
/* Hmmm: Do we release sig in case of rc != 0? */
|
||||
|
||||
if( !rc ) { /* and write it */
|
||||
PACKET pkt;
|
||||
|
||||
init_packet(&pkt);
|
||||
pkt.pkttype = PKT_SIGNATURE;
|
||||
pkt.pkt.signature = sig;
|
||||
rc = build_packet( out, &pkt );
|
||||
if( !rc && is_status_enabled() ) {
|
||||
print_status_sig_created ( sk, sig, status_char );
|
||||
}
|
||||
free_packet( &pkt );
|
||||
if( rc )
|
||||
log_error("build signature packet failed: %s\n", gpg_errstr(rc) );
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/****************
|
||||
* Sign the files whose names are in FILENAME.
|
||||
@ -360,7 +450,7 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr,
|
||||
|
||||
for( sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) {
|
||||
PKT_secret_key *sk = sk_rover->sk;
|
||||
gcry_md_enable(mfx.md, hash_for(sk->pubkey_algo));
|
||||
gcry_md_enable(mfx.md, hash_for(sk->pubkey_algo, sk->version ));
|
||||
}
|
||||
|
||||
if( !multifile )
|
||||
@ -385,6 +475,7 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr,
|
||||
iobuf_push_filter( out, encrypt_filter, &efx );
|
||||
}
|
||||
|
||||
/* Select a compress algorithm */
|
||||
if( opt.compress && !outfile && ( !detached || opt.compress_sigs) ) {
|
||||
if( !compr_algo )
|
||||
; /* don't use compression */
|
||||
@ -397,6 +488,7 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr,
|
||||
}
|
||||
}
|
||||
|
||||
/* Build one-pass signature packets when needed */
|
||||
if( !detached && !old_style ) {
|
||||
int skcount=0;
|
||||
/* loop over the secret certificates and build headers
|
||||
@ -417,7 +509,7 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr,
|
||||
sk = sk_rover->sk;
|
||||
ops = gcry_xcalloc( 1, sizeof *ops );
|
||||
ops->sig_class = opt.textmode && !outfile ? 0x01 : 0x00;
|
||||
ops->digest_algo = hash_for(sk->pubkey_algo);
|
||||
ops->digest_algo = hash_for(sk->pubkey_algo, sk->version);
|
||||
ops->pubkey_algo = sk->pubkey_algo;
|
||||
keyid_from_sk( sk, ops->keyid );
|
||||
ops->last = skcount == 1;
|
||||
@ -437,6 +529,8 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr,
|
||||
|
||||
/* setup the inner packet */
|
||||
if( detached ) {
|
||||
/* this is pretty much the same for old and new PGP. So no
|
||||
* need to cope with different packet ordering */
|
||||
if( multifile ) {
|
||||
STRLIST sl;
|
||||
|
||||
@ -468,9 +562,11 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr,
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* get the filename to be stored into the literal datapacket */
|
||||
if (!opt.no_literal) {
|
||||
if( fname || opt.set_filename ) {
|
||||
char *s = make_basename( opt.set_filename ? opt.set_filename : fname );
|
||||
char *s = make_basename( opt.set_filename ?
|
||||
opt.set_filename : fname );
|
||||
pt = gcry_xmalloc( sizeof *pt + strlen(s) - 1 );
|
||||
pt->namelen = strlen(s);
|
||||
memcpy(pt->name, s, pt->namelen );
|
||||
@ -490,7 +586,7 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr,
|
||||
if ( filesize >= IOBUF_FILELENGTH_LIMIT )
|
||||
filesize = 0;
|
||||
|
||||
/* because the text_filter modifies the length of the
|
||||
/* Because the text_filter modifies the length of the
|
||||
* data, it is not possible to know the used length
|
||||
* without a double read of the file - to avoid that
|
||||
* we simple use partial length packets.
|
||||
@ -511,7 +607,8 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr,
|
||||
pkt.pkt.plaintext = pt;
|
||||
/*cfx.datalen = filesize? calc_packet_length( &pkt ) : 0;*/
|
||||
if( (rc = build_packet( out, &pkt )) )
|
||||
log_error("build_packet(PLAINTEXT) failed: %s\n", gpg_errstr(rc) );
|
||||
log_error("build_packet(PLAINTEXT) failed: %s\n",
|
||||
gpg_errstr(rc) );
|
||||
pt->buf = NULL;
|
||||
}
|
||||
else {
|
||||
@ -520,100 +617,24 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr,
|
||||
while ((bytes_copied = iobuf_read(inp, copy_buffer, 4096)) != -1)
|
||||
if (iobuf_write(out, copy_buffer, bytes_copied) == -1) {
|
||||
rc = GPGERR_WRITE_FILE;
|
||||
log_error("copying input to output failed: %s\n", gpg_errstr(rc));
|
||||
log_error("copying input to output failed: %s\n",
|
||||
gpg_errstr(rc));
|
||||
break;
|
||||
}
|
||||
memset(copy_buffer, 0, 4096); /* burn buffer */
|
||||
}
|
||||
}
|
||||
|
||||
/* catch errors from above blocks */
|
||||
/* catch errors from above */
|
||||
if (rc)
|
||||
goto leave;
|
||||
|
||||
/* loop over the secret certificates */
|
||||
for( sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) {
|
||||
PKT_secret_key *sk;
|
||||
PKT_signature *sig;
|
||||
GCRY_MD_HD md;
|
||||
|
||||
sk = sk_rover->sk;
|
||||
|
||||
/* build the signature packet */
|
||||
/* fixme: this code is partly duplicated in make_keysig_packet */
|
||||
sig = gcry_xcalloc( 1, sizeof *sig );
|
||||
sig->version = old_style || opt.force_v3_sigs ? 3 : sk->version;
|
||||
keyid_from_sk( sk, sig->keyid );
|
||||
sig->digest_algo = hash_for(sk->pubkey_algo);
|
||||
sig->pubkey_algo = sk->pubkey_algo;
|
||||
sig->timestamp = make_timestamp();
|
||||
sig->sig_class = opt.textmode && !outfile? 0x01 : 0x00;
|
||||
|
||||
md = gcry_md_copy( mfx.md );
|
||||
if( !md )
|
||||
BUG();
|
||||
|
||||
if( sig->version >= 4 ) {
|
||||
build_sig_subpkt_from_sig( sig );
|
||||
gcry_md_putc( md, sig->version );
|
||||
}
|
||||
|
||||
mk_notation_and_policy( sig );
|
||||
|
||||
gcry_md_putc( md, sig->sig_class );
|
||||
if( sig->version < 4 ) {
|
||||
u32 a = sig->timestamp;
|
||||
gcry_md_putc( md, (a >> 24) & 0xff );
|
||||
gcry_md_putc( md, (a >> 16) & 0xff );
|
||||
gcry_md_putc( md, (a >> 8) & 0xff );
|
||||
gcry_md_putc( md, a & 0xff );
|
||||
}
|
||||
else {
|
||||
byte buf[6];
|
||||
size_t n;
|
||||
|
||||
gcry_md_putc( md, sig->pubkey_algo );
|
||||
gcry_md_putc( md, sig->digest_algo );
|
||||
if( sig->hashed_data ) {
|
||||
n = (sig->hashed_data[0] << 8) | sig->hashed_data[1];
|
||||
gcry_md_write( md, sig->hashed_data, n+2 );
|
||||
n += 6;
|
||||
}
|
||||
else {
|
||||
gcry_md_putc( md, 0 ); /* always hash the length of the subpacket*/
|
||||
gcry_md_putc( md, 0 );
|
||||
n = 6;
|
||||
}
|
||||
/* add some magic */
|
||||
buf[0] = sig->version;
|
||||
buf[1] = 0xff;
|
||||
buf[2] = n >> 24; /* hmmm, n is only 16 bit, so this is always 0 */
|
||||
buf[3] = n >> 16;
|
||||
buf[4] = n >> 8;
|
||||
buf[5] = n;
|
||||
gcry_md_write( md, buf, 6 );
|
||||
|
||||
}
|
||||
gcry_md_final( md );
|
||||
|
||||
rc = do_sign( sk, sig, md, hash_for(sig->pubkey_algo) );
|
||||
gcry_md_close( md );
|
||||
|
||||
if( !rc ) { /* and write it */
|
||||
init_packet(&pkt);
|
||||
pkt.pkttype = PKT_SIGNATURE;
|
||||
pkt.pkt.signature = sig;
|
||||
rc = build_packet( out, &pkt );
|
||||
if( !rc && is_status_enabled() ) {
|
||||
print_status_sig_created ( sk, sig, detached ? 'D':'S');
|
||||
}
|
||||
free_packet( &pkt );
|
||||
if( rc )
|
||||
log_error("build signature packet failed: %s\n", gpg_errstr(rc) );
|
||||
}
|
||||
if( rc )
|
||||
goto leave;
|
||||
|
||||
/* write all the signature packets */
|
||||
for( sk_rover = sk_list; sk_rover && !rc ; sk_rover = sk_rover->next ) {
|
||||
rc = write_one_signature( out, sk_rover->sk,
|
||||
old_style, outfile, mfx.md,
|
||||
opt.textmode && !outfile? 0x01 : 0x00,
|
||||
detached ? 'D':'S' );
|
||||
}
|
||||
|
||||
|
||||
@ -626,6 +647,7 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr,
|
||||
gcry_md_close( mfx.md );
|
||||
release_sk_list( sk_list );
|
||||
release_pk_list( pk_list );
|
||||
/* FIXME: Did we release the efx.cfx.dek ? */
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -679,7 +701,7 @@ clearsign_file( const char *fname, STRLIST locusr, const char *outfile )
|
||||
|
||||
for( sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) {
|
||||
PKT_secret_key *sk = sk_rover->sk;
|
||||
if( hash_for(sk->pubkey_algo) == GCRY_MD_MD5 )
|
||||
if( hash_for(sk->pubkey_algo, sk->version) == GCRY_MD_MD5 )
|
||||
only_md5 = 1;
|
||||
else {
|
||||
only_md5 = 0;
|
||||
@ -697,7 +719,7 @@ clearsign_file( const char *fname, STRLIST locusr, const char *outfile )
|
||||
iobuf_writestr(out, "Hash: " );
|
||||
for( sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) {
|
||||
PKT_secret_key *sk = sk_rover->sk;
|
||||
int i = hash_for(sk->pubkey_algo);
|
||||
int i = hash_for(sk->pubkey_algo, sk->version);
|
||||
|
||||
if( !hashs_seen[ i & 0xff ] ) {
|
||||
if( !openpgp_md_test_algo( i ) ) {
|
||||
@ -723,7 +745,7 @@ clearsign_file( const char *fname, STRLIST locusr, const char *outfile )
|
||||
BUG();
|
||||
for( sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) {
|
||||
PKT_secret_key *sk = sk_rover->sk;
|
||||
gcry_md_enable(textmd, hash_for(sk->pubkey_algo));
|
||||
gcry_md_enable(textmd, hash_for(sk->pubkey_algo, sk->version));
|
||||
}
|
||||
if ( DBG_HASHING )
|
||||
gcry_md_start_debug( textmd, "clearsign" );
|
||||
@ -735,90 +757,14 @@ clearsign_file( const char *fname, STRLIST locusr, const char *outfile )
|
||||
afx.what = 2;
|
||||
iobuf_push_filter( out, armor_filter, &afx );
|
||||
|
||||
/* loop over the secret certificates */
|
||||
for( sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) {
|
||||
PKT_secret_key *sk;
|
||||
PKT_signature *sig;
|
||||
GCRY_MD_HD md;
|
||||
|
||||
sk = sk_rover->sk;
|
||||
|
||||
/* build the signature packet */
|
||||
/* fixme: this code is duplicated above */
|
||||
sig = gcry_xcalloc( 1, sizeof *sig );
|
||||
sig->version = old_style || opt.force_v3_sigs ? 3 : sk->version;
|
||||
keyid_from_sk( sk, sig->keyid );
|
||||
sig->digest_algo = hash_for(sk->pubkey_algo);
|
||||
sig->pubkey_algo = sk->pubkey_algo;
|
||||
sig->timestamp = make_timestamp();
|
||||
sig->sig_class = 0x01;
|
||||
|
||||
md = gcry_md_copy( textmd );
|
||||
if( !md )
|
||||
BUG();
|
||||
if( sig->version >= 4 ) {
|
||||
build_sig_subpkt_from_sig( sig );
|
||||
gcry_md_putc( md, sig->version );
|
||||
/* write all the signature packets */
|
||||
for( sk_rover = sk_list; sk_rover && !rc ; sk_rover = sk_rover->next ) {
|
||||
rc = write_one_signature( out, sk_rover->sk,
|
||||
old_style, outfile, textmd,
|
||||
0x01,
|
||||
'C' );
|
||||
}
|
||||
|
||||
mk_notation_and_policy( sig );
|
||||
|
||||
gcry_md_putc( md, sig->sig_class );
|
||||
if( sig->version < 4 ) {
|
||||
u32 a = sig->timestamp;
|
||||
gcry_md_putc( md, (a >> 24) & 0xff );
|
||||
gcry_md_putc( md, (a >> 16) & 0xff );
|
||||
gcry_md_putc( md, (a >> 8) & 0xff );
|
||||
gcry_md_putc( md, a & 0xff );
|
||||
}
|
||||
else {
|
||||
byte buf[6];
|
||||
size_t n;
|
||||
|
||||
gcry_md_putc( md, sig->pubkey_algo );
|
||||
gcry_md_putc( md, sig->digest_algo );
|
||||
if( sig->hashed_data ) {
|
||||
n = (sig->hashed_data[0] << 8) | sig->hashed_data[1];
|
||||
gcry_md_write( md, sig->hashed_data, n+2 );
|
||||
n += 6;
|
||||
}
|
||||
else {
|
||||
gcry_md_putc( md, 0 ); /* always hash the length of the subpacket*/
|
||||
gcry_md_putc( md, 0 );
|
||||
n = 6;
|
||||
}
|
||||
/* add some magic */
|
||||
buf[0] = sig->version;
|
||||
buf[1] = 0xff;
|
||||
buf[2] = n >> 24; /* hmmm, n is only 16 bit, so this is always 0 */
|
||||
buf[3] = n >> 16;
|
||||
buf[4] = n >> 8;
|
||||
buf[5] = n;
|
||||
gcry_md_write( md, buf, 6 );
|
||||
|
||||
}
|
||||
gcry_md_final( md );
|
||||
|
||||
rc = do_sign( sk, sig, md, hash_for(sig->pubkey_algo) );
|
||||
gcry_md_close( md );
|
||||
|
||||
if( !rc ) { /* and write it */
|
||||
init_packet(&pkt);
|
||||
pkt.pkttype = PKT_SIGNATURE;
|
||||
pkt.pkt.signature = sig;
|
||||
rc = build_packet( out, &pkt );
|
||||
if( !rc && is_status_enabled() ) {
|
||||
print_status_sig_created ( sk, sig, 'C');
|
||||
}
|
||||
free_packet( &pkt );
|
||||
if( rc )
|
||||
log_error("build signature packet failed: %s\n", gpg_errstr(rc) );
|
||||
}
|
||||
if( rc )
|
||||
goto leave;
|
||||
}
|
||||
|
||||
|
||||
leave:
|
||||
if( rc )
|
||||
iobuf_cancel(out);
|
||||
|
@ -50,7 +50,7 @@ release_sk_list( SK_LIST sk_list )
|
||||
|
||||
int
|
||||
build_sk_list( STRLIST locusr, SK_LIST *ret_sk_list, int unlock,
|
||||
unsigned use )
|
||||
unsigned int use )
|
||||
{
|
||||
SK_LIST sk_list = NULL;
|
||||
int rc;
|
||||
@ -64,9 +64,11 @@ build_sk_list( STRLIST locusr, SK_LIST *ret_sk_list, int unlock,
|
||||
free_secret_key( sk ); sk = NULL;
|
||||
log_error("no default secret key: %s\n", gpg_errstr(rc) );
|
||||
}
|
||||
else if( !(rc=openpgp_pk_test_algo(sk->pubkey_algo, use)) ) {
|
||||
else if( !(rc=openpgp_pk_test_algo(sk->pubkey_algo,
|
||||
sk->pubkey_usage)) ) {
|
||||
SK_LIST r;
|
||||
if( sk->version == 4 && (use & GCRY_PK_USAGE_SIGN )
|
||||
|
||||
if( sk->version == 4 && (sk->pubkey_usage & GCRY_PK_USAGE_SIGN )
|
||||
&& sk->pubkey_algo == GCRY_PK_ELG_E ) {
|
||||
log_info("this is a PGP generated "
|
||||
"ElGamal key which is NOT secure for signatures!\n");
|
||||
@ -95,9 +97,10 @@ build_sk_list( STRLIST locusr, SK_LIST *ret_sk_list, int unlock,
|
||||
free_secret_key( sk ); sk = NULL;
|
||||
log_error(_("skipped `%s': %s\n"), locusr->d, gpg_errstr(rc) );
|
||||
}
|
||||
else if( !(rc=openpgp_pk_test_algo(sk->pubkey_algo, use)) ) {
|
||||
else if( !(rc=openpgp_pk_test_algo(sk->pubkey_algo,
|
||||
sk->pubkey_usage)) ) {
|
||||
SK_LIST r;
|
||||
if( sk->version == 4 && (use & GCRY_PK_USAGE_SIGN)
|
||||
if( sk->version == 4 && (sk->pubkey_usage & GCRY_PK_USAGE_SIGN)
|
||||
&& sk->pubkey_algo == GCRY_PK_ELG_E ) {
|
||||
log_info(_("skipped `%s': this is a PGP generated "
|
||||
"ElGamal key which is not secure for signatures!\n"),
|
||||
|
@ -74,8 +74,9 @@ set_status_fd ( int newfd )
|
||||
{
|
||||
fd = newfd;
|
||||
if ( fd != -1 ) {
|
||||
#if 0
|
||||
#warning fixme - progress functions
|
||||
/* Has to be fixed in libgcrypt */
|
||||
#if 0
|
||||
register_primegen_progress ( progress_cb, "primegen" );
|
||||
register_pk_dsa_progress ( progress_cb, "pk_dsa" );
|
||||
register_pk_elg_progress ( progress_cb, "pk_elg" );
|
||||
|
@ -24,6 +24,7 @@ int tty_batchmode( int onoff );
|
||||
void tty_printf( const char *fmt, ... );
|
||||
void tty_print_string( byte *p, size_t n );
|
||||
void tty_print_utf8_string( byte *p, size_t n );
|
||||
void tty_print_utf8_string2( byte *p, size_t n, size_t max_n );
|
||||
char *tty_get( const char *prompt );
|
||||
char *tty_get_hidden( const char *prompt );
|
||||
void tty_kill_prompt(void);
|
||||
|
Loading…
x
Reference in New Issue
Block a user