mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
very first release
This commit is contained in:
parent
ee8d92fefa
commit
cb5459aed7
2
INSTALL
2
INSTALL
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
./configure --enable-m-debug
|
./configure --enable-m-debug
|
||||||
|
|
||||||
to ebanle the integrated malloc debugging stuff.
|
to enable the integrated malloc debugging stuff.
|
||||||
|
|
||||||
|
|
||||||
2) Run make:
|
2) Run make:
|
||||||
|
133
README
133
README
@ -1,20 +1,20 @@
|
|||||||
|
|
||||||
G10 - The GNU Enryption and Signing Tool
|
G10 - The GNU Encryption and Signing Tool
|
||||||
------------------------------------------
|
------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
THIS IS VERSION IS ONLY a TEST VERSION ! YOU SHOULD NOT
|
THIS IS VERSION IS ONLY A TEST VERSION ! YOU SHOULD NOT
|
||||||
USE IT FOR OTHER PURPOSES THAN EVALUATING THE CURRENT CODE.
|
USE IT FOR OTHER PURPOSES THAN EVALUATING THE CURRENT CODE.
|
||||||
|
|
||||||
|
* Only some parts work.
|
||||||
|
|
||||||
* The data format may change in the next version!
|
* The data format may change in the next version!
|
||||||
|
|
||||||
* The code to generate keys is not secure!
|
* Some features are not yet implemented
|
||||||
|
|
||||||
* Some features are not implemented
|
|
||||||
|
|
||||||
|
|
||||||
I provide this version as a reality check to start discussion.
|
I provide this version as a reality check to start discussion.
|
||||||
Please subscribe to g10@net.lut.ac.uk be sending a mail with
|
Please subscribe to g10@net.lut.ac.uk by sending a mail with
|
||||||
the word "subscribe" in the body to "g10-request@net.lut.ac.uk".
|
the word "subscribe" in the body to "g10-request@net.lut.ac.uk".
|
||||||
|
|
||||||
|
|
||||||
@ -25,26 +25,139 @@
|
|||||||
it cannot be compatible to old PGP versions, because those use
|
it cannot be compatible to old PGP versions, because those use
|
||||||
IDEA (which is worldwide patented) and RSA (which is patented in
|
IDEA (which is worldwide patented) and RSA (which is patented in
|
||||||
the United States until Sep 20, 2000). I'm sorry about this, but
|
the United States until Sep 20, 2000). I'm sorry about this, but
|
||||||
this is the world we have created (e.g. by using propiertary software).
|
this is the world we have created (e.g. by using proprietary software).
|
||||||
|
|
||||||
|
|
||||||
Because the OpenPGP standard is still a draft, G10 is not yet
|
Because the OpenPGP standard is still a draft, G10 is not yet
|
||||||
compatible to it (or PGP 5) - but it will. The data structures
|
compatible to it (or PGP 5) - but it will. The data structures
|
||||||
used are compatible with PGP 2.x, so it can parse an list such files
|
used are compatible with PGP 2.x, so it can parse an list such files
|
||||||
and PGP should be able to parse data created by G10 and complain
|
and PGP should be able to parse data created by G10 and complain
|
||||||
about unsupported alogorithms.
|
about unsupported algorithms.
|
||||||
|
|
||||||
The default algorithms used by G10 are ElGamal for public-key
|
The default algorithms used by G10 are ElGamal for public-key
|
||||||
encryption and signing; Blowfish with a 160 bit key for protecting
|
encryption and signing; Blowfish with a 160 bit key for protecting
|
||||||
the secret-key components, conventional and session encryption;
|
the secret-key components, conventional and session encryption;
|
||||||
RIPE MD-160 to create message digest. DSA, SHA-1 and CAST are
|
RIPE MD-160 to create message digest. DSA, SHA-1 and CAST are
|
||||||
also implemented, but not used on default. I decided not
|
also implemented, but not used on default. I decided not
|
||||||
to use DSA as default signing algorithm, cecause it allows only for
|
to use DSA as default signing algorithm, because it allows only for
|
||||||
1024 bit keys and this may be not enough in a couple of years.
|
1024 bit keys and this may be not enough in a couple of years.
|
||||||
|
|
||||||
Key generation takes a long time and should be improved!
|
|
||||||
|
Resources
|
||||||
|
---------
|
||||||
|
G10 needs a directory "~/.g10" to store the default keyrings
|
||||||
|
and other files.
|
||||||
|
|
||||||
|
|
||||||
|
Key Generation
|
||||||
|
--------------
|
||||||
|
Create a key pair with this command:
|
||||||
|
|
||||||
|
g10 --gen-key
|
||||||
|
|
||||||
|
This asks some questions and then starts key generation. To create
|
||||||
|
good random numbers for prime number generation, it uses a /dev/random
|
||||||
|
which will emit only bytes if the kernel can gather enough entropy.
|
||||||
|
If you see no progress, you should start some other activities such
|
||||||
|
as a mouse moves or a "find /". Because we have no hardware device
|
||||||
|
to generate random we have to use this method.
|
||||||
|
|
||||||
|
Key generation shows progress by printing different characters to
|
||||||
|
stderr:
|
||||||
|
"." Miller-Rabin test failed.
|
||||||
|
"+" Miller-Rabin test succeeded.
|
||||||
|
"!" Reloading the pool with fresh prime numbers
|
||||||
|
"^" Checking a new value for the generator
|
||||||
|
"~" Issued during generator checks
|
||||||
|
"<" Size of one factor decreased
|
||||||
|
">" Size of one factor increased
|
||||||
|
|
||||||
|
The prime number for ElGamal is generated this way:
|
||||||
|
|
||||||
|
1) Make a prime number q of 160, 200, 240 bits (depending on the keysize).
|
||||||
|
2) Select the length of the other prime factors to be at least the size
|
||||||
|
of q and calculate the number of prime factors needed
|
||||||
|
3) Make a pool of prime number, each of the length determined in step 2
|
||||||
|
4) Get a new permutation out of the pool or continue with step 3
|
||||||
|
if we have tested all permutations.
|
||||||
|
5) Calculate a candidate prime p = 2 * q * p[1] * ... * p[n] + 1
|
||||||
|
6) Check that this prime has the correct length (this may change q if
|
||||||
|
it seems not to be possible to make a prime of the desired length)
|
||||||
|
7) Check whether this is a prime using trial divisions and the
|
||||||
|
Miller-Rabin test.
|
||||||
|
8) Continue with step 4 if we did not find a prime in step 7.
|
||||||
|
9) Find a generator for that prime.
|
||||||
|
|
||||||
|
|
||||||
|
Signatures
|
||||||
|
----------
|
||||||
|
To create a signature, use this:
|
||||||
|
|
||||||
|
g10 -s file
|
||||||
|
|
||||||
|
This creates a file file.g10 which is compressed and has a signature
|
||||||
|
attached.
|
||||||
|
|
||||||
|
g10 -sa file
|
||||||
|
|
||||||
|
Same as above, but file.g10 is ascii armored.
|
||||||
|
|
||||||
|
g10 -s -o out file
|
||||||
|
|
||||||
|
Creates a signature of file, but writes the output to the file "out".
|
||||||
|
|
||||||
|
Encryption
|
||||||
|
----------
|
||||||
|
To encrypt data use this:
|
||||||
|
|
||||||
|
g10 -e -r heine file
|
||||||
|
|
||||||
|
This encrypts files with the public key of "heine" and writes it
|
||||||
|
to "file.g10"
|
||||||
|
|
||||||
|
echo "hallo" | g10 -ea -r heine | mail heine
|
||||||
|
|
||||||
|
Ditto, but encrypts "hallo\n" and mails it as ascii armored message.
|
||||||
|
|
||||||
|
|
||||||
|
Debug Flags
|
||||||
|
-----------
|
||||||
|
Use the option "--debug n" to output debug informations. This option
|
||||||
|
can be used multiple times, all values are ORed; n maybe prefixed with
|
||||||
|
0x to use hex-values.
|
||||||
|
|
||||||
|
value used for
|
||||||
|
----- ----------------------------------------------
|
||||||
|
1 packet reading/writing
|
||||||
|
2 MPI details
|
||||||
|
4 ciphers and primes (may reveal sensitive data)
|
||||||
|
8 iobuf filter functions
|
||||||
|
16 iobuf stuff
|
||||||
|
32 memory allocation stuff
|
||||||
|
64 caching
|
||||||
|
128 show memory statistics at exit
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Other Notes
|
||||||
|
-----------
|
||||||
|
This is work in progress, so you may find duplicated code fragments,
|
||||||
|
ugly data structures, weird usage of filenames and other thinks.
|
||||||
|
I will run "indent" over the source when making a real distribution,
|
||||||
|
but for now I stick to my own formatting rules.
|
||||||
|
|
||||||
|
Compression does not work always; this is the reason that "-z 0"
|
||||||
|
is the default.
|
||||||
|
|
||||||
|
This will be cleaned up of course.
|
||||||
|
|
||||||
|
The primary FTP site is "ftp://ftp.guug.de/pub/gcrypt/"
|
||||||
|
The primary WWW page is "http://www.d.shuttle.de/isil/g10.html"
|
||||||
|
|
||||||
|
Please direct bug reports to <g10-bugs@isil.d.shuttle.de> or better
|
||||||
|
post them to the mailing list <g10@net.lut.ac.uk>.
|
||||||
|
|
||||||
|
Have fun
|
||||||
|
|
||||||
|
Werner
|
||||||
|
|
||||||
|
1
TODO
1
TODO
@ -5,7 +5,6 @@
|
|||||||
* add a way to difference between errors and eof in the underflow/flush
|
* add a way to difference between errors and eof in the underflow/flush
|
||||||
function of iobuf.
|
function of iobuf.
|
||||||
* check that all output is filtered when displayed.
|
* check that all output is filtered when displayed.
|
||||||
* keyring editing
|
|
||||||
* add trust stuff
|
* add trust stuff
|
||||||
* make ttyio.c work (hide passwords etc..)
|
* make ttyio.c work (hide passwords etc..)
|
||||||
* use correct ASN values for DEK encoding
|
* use correct ASN values for DEK encoding
|
||||||
|
@ -149,7 +149,7 @@ elg_generate( ELG_public_key *pk, ELG_secret_key *sk, unsigned nbits )
|
|||||||
do {
|
do {
|
||||||
if( DBG_CIPHER )
|
if( DBG_CIPHER )
|
||||||
fputc('.', stderr);
|
fputc('.', stderr);
|
||||||
mpi_set_bytes( x, nbits, get_random_byte, 1 ); /* fixme: should be 2 */
|
mpi_set_bytes( x, nbits, get_random_byte, 2 );
|
||||||
} while( !( mpi_cmp_ui( x, 0 )>0 && mpi_cmp( x, p_min1 )<0 ) );
|
} while( !( mpi_cmp_ui( x, 0 )>0 && mpi_cmp( x, p_min1 )<0 ) );
|
||||||
|
|
||||||
y = mpi_alloc(nbits/BITS_PER_MPI_LIMB);
|
y = mpi_alloc(nbits/BITS_PER_MPI_LIMB);
|
||||||
|
@ -52,7 +52,7 @@ generate_public_prime( unsigned nbits )
|
|||||||
{
|
{
|
||||||
MPI prime;
|
MPI prime;
|
||||||
|
|
||||||
prime = gen_prime( nbits, 0, 1 ); /* fixme: change to 2 */
|
prime = gen_prime( nbits, 0, 2 );
|
||||||
fputc('\n', stderr);
|
fputc('\n', stderr);
|
||||||
return prime;
|
return prime;
|
||||||
}
|
}
|
||||||
@ -70,6 +70,8 @@ generate_elg_prime( unsigned pbits, unsigned qbits, MPI g )
|
|||||||
MPI prime; /* prime test value */
|
MPI prime; /* prime test value */
|
||||||
byte *perms = NULL;
|
byte *perms = NULL;
|
||||||
int i, j;
|
int i, j;
|
||||||
|
int count1, count2;
|
||||||
|
unsigned nprime;
|
||||||
|
|
||||||
/* find number of needed prime factors */
|
/* find number of needed prime factors */
|
||||||
for(n=1; (pbits - qbits - 1) / n >= qbits; n++ )
|
for(n=1; (pbits - qbits - 1) / n >= qbits; n++ )
|
||||||
@ -80,33 +82,32 @@ generate_elg_prime( unsigned pbits, unsigned qbits, MPI g )
|
|||||||
fbits = (pbits - qbits -1) / n;
|
fbits = (pbits - qbits -1) / n;
|
||||||
while( qbits + n*fbits < pbits )
|
while( qbits + n*fbits < pbits )
|
||||||
qbits++;
|
qbits++;
|
||||||
qbits++; /* one mpre to increase tzhe chance to get a weel formed prime*/
|
if( DBG_CIPHER )
|
||||||
log_debug("gen prime: pbits=%u qbits=%u fbits=%u n=%d\n",
|
log_debug("gen prime: pbits=%u qbits=%u fbits=%u n=%d\n",
|
||||||
pbits, qbits, fbits, n );
|
pbits, qbits, fbits, n );
|
||||||
|
|
||||||
prime = mpi_alloc( (pbits + BITS_PER_MPI_LIMB - 1) / BITS_PER_MPI_LIMB );
|
prime = mpi_alloc( (pbits + BITS_PER_MPI_LIMB - 1) / BITS_PER_MPI_LIMB );
|
||||||
q = gen_prime( qbits, 0, 0 ); /* fixme: should be 2 */
|
q = gen_prime( qbits, 0, 2 );
|
||||||
fputc('\n', stderr);
|
|
||||||
|
|
||||||
/* allocate an array to hold the factors + 2 for later usage */
|
/* allocate an array to hold the factors + 2 for later usage */
|
||||||
factors = m_alloc_clear( (n+2) * sizeof *factors );
|
factors = m_alloc_clear( (n+2) * sizeof *factors );
|
||||||
|
|
||||||
/* make a pool of 2n+5 primes (this is an arbitrary value) */
|
/* make a pool of 3n+5 primes (this is an arbitrary value) */
|
||||||
m = n*2+5;
|
m = n*3+5;
|
||||||
if( m < 20 )
|
if( m < 25 )
|
||||||
m = 20;
|
m = 25;
|
||||||
pool = m_alloc_clear( m * sizeof *pool );
|
pool = m_alloc_clear( m * sizeof *pool );
|
||||||
|
|
||||||
/* permutate over the pool of primes */
|
/* permutate over the pool of primes */
|
||||||
|
count1=count2=0;
|
||||||
do {
|
do {
|
||||||
next_try:
|
next_try:
|
||||||
if( !perms ) {
|
if( !perms ) {
|
||||||
/* allocate new primes */
|
/* allocate new primes */
|
||||||
for(i=0; i < m; i++ ) {
|
for(i=0; i < m; i++ ) {
|
||||||
mpi_free(pool[i]);
|
mpi_free(pool[i]);
|
||||||
pool[i] = gen_prime( fbits, 0, 0 ); /* fixme: should be 2 */
|
pool[i] = gen_prime( fbits, 0, 2 );
|
||||||
}
|
}
|
||||||
fputc('\n', stderr);
|
|
||||||
/* init m_out_of_n() */
|
/* init m_out_of_n() */
|
||||||
perms = m_alloc_clear( m );
|
perms = m_alloc_clear( m );
|
||||||
for(i=0; i < n; i++ ) {
|
for(i=0; i < n; i++ ) {
|
||||||
@ -131,18 +132,43 @@ generate_elg_prime( unsigned pbits, unsigned qbits, MPI g )
|
|||||||
for(i=0; i < n; i++ )
|
for(i=0; i < n; i++ )
|
||||||
mpi_mul( prime, prime, factors[i] );
|
mpi_mul( prime, prime, factors[i] );
|
||||||
mpi_add_ui( prime, prime, 1 );
|
mpi_add_ui( prime, prime, 1 );
|
||||||
} while( !( mpi_get_nbits( prime ) == pbits && check_prime( prime )) );
|
nprime = mpi_get_nbits(prime);
|
||||||
putc('\n', stderr);
|
if( nprime < pbits ) {
|
||||||
|
if( ++count1 > 20 ) {
|
||||||
|
count1 = 0;
|
||||||
|
qbits++;
|
||||||
|
fputc('>', stderr);
|
||||||
|
q = gen_prime( qbits, 0, 2 );
|
||||||
|
goto next_try;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
count1 = 0;
|
||||||
|
if( nprime > pbits ) {
|
||||||
|
if( ++count2 > 20 ) {
|
||||||
|
count2 = 0;
|
||||||
|
qbits--;
|
||||||
|
fputc('<', stderr);
|
||||||
|
q = gen_prime( qbits, 0, 2 );
|
||||||
|
goto next_try;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
count2 = 0;
|
||||||
|
} while( !(nprime == pbits && check_prime( prime )) );
|
||||||
|
|
||||||
|
|
||||||
log_mpidump( "prime : ", prime );
|
if( DBG_CIPHER ) {
|
||||||
log_mpidump( "factor q: ", q );
|
putc('\n', stderr);
|
||||||
for(i=0; i < n; i++ )
|
log_mpidump( "prime : ", prime );
|
||||||
log_mpidump( "factor pi: ", factors[i] );
|
log_mpidump( "factor q: ", q );
|
||||||
log_debug("bit sizes: prime=%u, q=%u",mpi_get_nbits(prime), mpi_get_nbits(q) );
|
for(i=0; i < n; i++ )
|
||||||
for(i=0; i < n; i++ )
|
log_mpidump( "factor pi: ", factors[i] );
|
||||||
fprintf(stderr, ", p%d=%u", i, mpi_get_nbits(factors[i]) );
|
log_debug("bit sizes: prime=%u, q=%u", mpi_get_nbits(prime), mpi_get_nbits(q) );
|
||||||
putc('\n', stderr);
|
for(i=0; i < n; i++ )
|
||||||
|
fprintf(stderr, ", p%d=%u", i, mpi_get_nbits(factors[i]) );
|
||||||
|
putc('\n', stderr);
|
||||||
|
}
|
||||||
|
|
||||||
if( g ) { /* create a generator (start with 3)*/
|
if( g ) { /* create a generator (start with 3)*/
|
||||||
MPI tmp = mpi_alloc( mpi_get_nlimbs(prime) );
|
MPI tmp = mpi_alloc( mpi_get_nlimbs(prime) );
|
||||||
@ -155,22 +181,30 @@ generate_elg_prime( unsigned pbits, unsigned qbits, MPI g )
|
|||||||
mpi_set_ui(g,2);
|
mpi_set_ui(g,2);
|
||||||
do {
|
do {
|
||||||
mpi_add_ui(g, g, 1);
|
mpi_add_ui(g, g, 1);
|
||||||
log_mpidump("checking g: ", g );
|
if( DBG_CIPHER ) {
|
||||||
|
log_debug("checking g: ");
|
||||||
|
mpi_print( stderr, g, 1 );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
fputc('^', stderr);
|
||||||
for(i=0; i < n+2; i++ ) {
|
for(i=0; i < n+2; i++ ) {
|
||||||
log_mpidump(" against: ", factors[i] );
|
fputc('~', stderr);
|
||||||
mpi_fdiv_q(tmp, pmin1, factors[i] );
|
mpi_fdiv_q(tmp, pmin1, factors[i] );
|
||||||
/* (no mpi_pow(), but it is okay to use this with mod prime) */
|
/* (no mpi_pow(), but it is okay to use this with mod prime) */
|
||||||
mpi_powm(b, g, tmp, prime );
|
mpi_powm(b, g, tmp, prime );
|
||||||
if( !mpi_cmp_ui(b, 1) )
|
if( !mpi_cmp_ui(b, 1) )
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while( i < n );
|
if( DBG_CIPHER )
|
||||||
|
fputc('\n', stderr);
|
||||||
|
} while( i < n+2 );
|
||||||
mpi_free(factors[n+1]);
|
mpi_free(factors[n+1]);
|
||||||
mpi_free(tmp);
|
mpi_free(tmp);
|
||||||
mpi_free(b);
|
mpi_free(b);
|
||||||
mpi_free(pmin1);
|
mpi_free(pmin1);
|
||||||
log_mpidump("found g: ", g );
|
|
||||||
}
|
}
|
||||||
|
if( !DBG_CIPHER )
|
||||||
|
putc('\n', stderr);
|
||||||
|
|
||||||
m_free( factors ); /* (factors are shallow copies) */
|
m_free( factors ); /* (factors are shallow copies) */
|
||||||
for(i=0; i < m; i++ )
|
for(i=0; i < m; i++ )
|
||||||
@ -232,7 +266,6 @@ gen_prime( unsigned nbits, int secret, int randomlevel )
|
|||||||
}
|
}
|
||||||
if( x )
|
if( x )
|
||||||
continue; /* found a multiple of a already known prime */
|
continue; /* found a multiple of a already known prime */
|
||||||
fputc('.', stderr);
|
|
||||||
|
|
||||||
mpi_add_ui( prime, prime, step );
|
mpi_add_ui( prime, prime, step );
|
||||||
|
|
||||||
@ -267,6 +300,7 @@ gen_prime( unsigned nbits, int secret, int randomlevel )
|
|||||||
m_free(mods);
|
m_free(mods);
|
||||||
return prime;
|
return prime;
|
||||||
}
|
}
|
||||||
|
fputc('.', stderr);
|
||||||
}
|
}
|
||||||
fputc(':', stderr); /* restart with a new random value */
|
fputc(':', stderr); /* restart with a new random value */
|
||||||
}
|
}
|
||||||
@ -289,7 +323,6 @@ check_prime( MPI prime )
|
|||||||
if( mpi_divisible_ui( prime, x ) )
|
if( mpi_divisible_ui( prime, x ) )
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
fputc('.', stderr);
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
result = mpi_alloc( mpi_get_nlimbs(prime) );
|
result = mpi_alloc( mpi_get_nlimbs(prime) );
|
||||||
@ -308,6 +341,7 @@ check_prime( MPI prime )
|
|||||||
/* perform stronger tests */
|
/* perform stronger tests */
|
||||||
if( is_prime(prime, 5, &count ) )
|
if( is_prime(prime, 5, &count ) )
|
||||||
return 1; /* is probably a prime */
|
return 1; /* is probably a prime */
|
||||||
|
fputc('.', stderr);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
struct cache {
|
struct cache {
|
||||||
int len;
|
int len;
|
||||||
byte buffer[100]; /* fixme: should be allocalted with m_alloc_secure()*/
|
byte buffer[100]; /* fixme: should be allocated with m_alloc_secure()*/
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct cache cache[3];
|
static struct cache cache[3];
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
## Process this file with automake to produce Makefile.in
|
## Process this file with automake to produce Makefile.in
|
||||||
|
|
||||||
INCLUDES = -I$(top_srcdir)/include
|
INCLUDES = -I$(top_srcdir)/include
|
||||||
|
EXTRA_DIST = OPTIONS
|
||||||
|
|
||||||
bin_PROGRAMS = g10
|
bin_PROGRAMS = g10
|
||||||
|
|
||||||
|
@ -39,6 +39,7 @@ INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
|||||||
transform = @program_transform_name@
|
transform = @program_transform_name@
|
||||||
|
|
||||||
INCLUDES = -I$(top_srcdir)/include
|
INCLUDES = -I$(top_srcdir)/include
|
||||||
|
EXTRA_DIST = OPTIONS
|
||||||
|
|
||||||
bin_PROGRAMS = g10
|
bin_PROGRAMS = g10
|
||||||
|
|
||||||
|
135
g10/OPTIONS
Normal file
135
g10/OPTIONS
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
# This is a sample option file
|
||||||
|
#
|
||||||
|
# Unless you you specify which option file to use with the
|
||||||
|
# commandline option "--options filename", g10 uses per
|
||||||
|
# default the file ~/.g10/options.
|
||||||
|
#
|
||||||
|
# An option file can contain all long options which are
|
||||||
|
# available in G10. If the first non white space character of
|
||||||
|
# a line is a '#', this line is ignored. Empty lines are also
|
||||||
|
# ignored.
|
||||||
|
#
|
||||||
|
# Here is a list of all possible options. Not of all them make
|
||||||
|
# sense in an option file; consider this as a complete option
|
||||||
|
# reference
|
||||||
|
|
||||||
|
add-key
|
||||||
|
# add key to the public keyring
|
||||||
|
|
||||||
|
armor
|
||||||
|
# create ascii armored output
|
||||||
|
|
||||||
|
|
||||||
|
batch
|
||||||
|
# batch mode: never ask
|
||||||
|
|
||||||
|
cache-all
|
||||||
|
# hold everything in memory
|
||||||
|
|
||||||
|
change-passphrase
|
||||||
|
# change the passphrase of your secret keyring
|
||||||
|
|
||||||
|
check
|
||||||
|
# check a signature
|
||||||
|
|
||||||
|
check-key
|
||||||
|
# check signatures on a key in the keyring
|
||||||
|
|
||||||
|
debug value|hexvalue
|
||||||
|
# set debugging flags,
|
||||||
|
|
||||||
|
debug-all
|
||||||
|
# enable full debugging
|
||||||
|
|
||||||
|
decrypt
|
||||||
|
# decrypt data (default)
|
||||||
|
|
||||||
|
delete-key
|
||||||
|
# remove key from public keyring,
|
||||||
|
|
||||||
|
detach-sign
|
||||||
|
# make a detached signature,
|
||||||
|
|
||||||
|
dry-run
|
||||||
|
# don't make any changes
|
||||||
|
|
||||||
|
encrypt
|
||||||
|
# encrypt data
|
||||||
|
|
||||||
|
fingerprint
|
||||||
|
# show the fingerprints,
|
||||||
|
|
||||||
|
gen-key
|
||||||
|
# generate a new key pair,
|
||||||
|
|
||||||
|
gen-prime
|
||||||
|
# Generate a prime.
|
||||||
|
# With one argument: take it as the bitsize and make a simple prime of
|
||||||
|
# this size
|
||||||
|
# With two arguments: Generate a prime, usable for DL algorithms.
|
||||||
|
# With three arguments: same as above, but a third argument indicates
|
||||||
|
# taht a generator should also be calculated.
|
||||||
|
|
||||||
|
keyring filename
|
||||||
|
# add this filename to the list of keyrings
|
||||||
|
|
||||||
|
local-user user-string
|
||||||
|
# use this user-string to sign or decrypt
|
||||||
|
|
||||||
|
no
|
||||||
|
# assume no on most questions
|
||||||
|
|
||||||
|
no-armor
|
||||||
|
# Assume the input data is not in ascii armored format.
|
||||||
|
|
||||||
|
no-default-keyring
|
||||||
|
# Do not add the default keyrings to the list of keyrings
|
||||||
|
|
||||||
|
options filename
|
||||||
|
# Ignored in option files.
|
||||||
|
|
||||||
|
output filename
|
||||||
|
# use filename for output
|
||||||
|
|
||||||
|
print-mds
|
||||||
|
# print all message digests of all give filenames
|
||||||
|
|
||||||
|
remote-user
|
||||||
|
# use this user-id for encryption"
|
||||||
|
|
||||||
|
|
||||||
|
secret-keyring filename
|
||||||
|
# add filename to the list of secret keyrings
|
||||||
|
|
||||||
|
sign
|
||||||
|
# make a signature
|
||||||
|
|
||||||
|
sign-key
|
||||||
|
# make a signature on a key in the keyring
|
||||||
|
# Argument is the userid of the key to sign.
|
||||||
|
# This looks for the key, displays the key and checks all
|
||||||
|
# existing signatures of this key. If the key is not yet signed
|
||||||
|
# by the default user (or the users given with "-l"), the programm
|
||||||
|
# displays the information of the key again, together with
|
||||||
|
# it's fingerprint and asked wehter it should be signed. This question
|
||||||
|
# is repeated for all users specified with "-l". The key is then signed
|
||||||
|
# and the keyring which contains the key is updated.
|
||||||
|
|
||||||
|
store
|
||||||
|
# simply packs the input data into a rfc1991 packet format
|
||||||
|
|
||||||
|
symmetric
|
||||||
|
# encrypt the input only with the symmetric (conventional) cipher.
|
||||||
|
# This asks for a passphrase.
|
||||||
|
|
||||||
|
test
|
||||||
|
# Used for testing some parts of the program
|
||||||
|
|
||||||
|
verbose
|
||||||
|
# Give more informations suring processing. If used 2 times, the input data
|
||||||
|
# is listed in detail.
|
||||||
|
|
||||||
|
yes
|
||||||
|
# assume yes on most questions
|
||||||
|
|
||||||
|
|
17
g10/g10.c
17
g10/g10.c
@ -131,8 +131,9 @@ main( int argc, char **argv )
|
|||||||
{ 515, "fingerprint", 0, "show the fingerprints"},
|
{ 515, "fingerprint", 0, "show the fingerprints"},
|
||||||
{ 516, "print-mds" , 0, "print all message digests"},
|
{ 516, "print-mds" , 0, "print all message digests"},
|
||||||
{ 517, "secret-keyring" ,2, "add this secret keyring to the list" },
|
{ 517, "secret-keyring" ,2, "add this secret keyring to the list" },
|
||||||
{ 518, "config" , 2, "use this config file" },
|
{ 518, "options" , 2, "read options from file" },
|
||||||
{ 519, "no-armor", 0, "\r"},
|
{ 519, "no-armor", 0, "\r"},
|
||||||
|
{ 520, "no-default-keyring", 0, "\r" },
|
||||||
|
|
||||||
{0} };
|
{0} };
|
||||||
ARGPARSE_ARGS pargs;
|
ARGPARSE_ARGS pargs;
|
||||||
@ -155,9 +156,10 @@ main( int argc, char **argv )
|
|||||||
int parse_verbose = 0;
|
int parse_verbose = 0;
|
||||||
int default_config =1;
|
int default_config =1;
|
||||||
int errors=0;
|
int errors=0;
|
||||||
|
int default_keyring = 1;
|
||||||
|
|
||||||
|
|
||||||
opt.compress = -1; /* defaults to default compression level */
|
opt.compress = 0; /* defaults to no compression level */
|
||||||
|
|
||||||
/* check wether we have a config file on the commandline */
|
/* check wether we have a config file on the commandline */
|
||||||
orig_argc = argc;
|
orig_argc = argc;
|
||||||
@ -212,10 +214,7 @@ main( int argc, char **argv )
|
|||||||
case 'z': opt.compress = pargs.r.ret_int; break;
|
case 'z': opt.compress = pargs.r.ret_int; break;
|
||||||
case 'a': opt.armor = 1; opt.no_armor=0; break;
|
case 'a': opt.armor = 1; opt.no_armor=0; break;
|
||||||
case 'c': action = aSym; break;
|
case 'c': action = aSym; break;
|
||||||
case 'o': opt.outfile = pargs.r.ret_str;
|
case 'o': opt.outfile = pargs.r.ret_str; break;
|
||||||
if( opt.outfile[0] == '-' && !opt.outfile[1] )
|
|
||||||
opt.outfile_is_stdout = 1;
|
|
||||||
break;
|
|
||||||
case 'e': action = action == aSign? aSignEncr : aEncr; break;
|
case 'e': action = action == aSign? aSignEncr : aEncr; break;
|
||||||
case 'b': detached_sig = 1;
|
case 'b': detached_sig = 1;
|
||||||
/* fall trough */
|
/* fall trough */
|
||||||
@ -257,6 +256,7 @@ main( int argc, char **argv )
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 519: opt.no_armor=1; opt.armor=0; break;
|
case 519: opt.no_armor=1; opt.armor=0; break;
|
||||||
|
case 520: default_keyring = 0; break;
|
||||||
default : errors++; pargs.err = configfp? 1:2; break;
|
default : errors++; pargs.err = configfp? 1:2; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -280,12 +280,12 @@ main( int argc, char **argv )
|
|||||||
fputs(s, stderr);
|
fputs(s, stderr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !sec_nrings ) { /* add default secret rings */
|
if( !sec_nrings || default_keyring ) { /* add default secret rings */
|
||||||
char *p = make_filename("~/.g10", "secring.g10", NULL );
|
char *p = make_filename("~/.g10", "secring.g10", NULL );
|
||||||
add_secret_keyring(p);
|
add_secret_keyring(p);
|
||||||
m_free(p);
|
m_free(p);
|
||||||
}
|
}
|
||||||
if( !nrings ) { /* add default ring */
|
if( !nrings || default_keyring ) { /* add default ring */
|
||||||
char *p = make_filename("~/.g10", "pubring.g10", NULL );
|
char *p = make_filename("~/.g10", "pubring.g10", NULL );
|
||||||
add_keyring(p);
|
add_keyring(p);
|
||||||
m_free(p);
|
m_free(p);
|
||||||
@ -331,6 +331,7 @@ main( int argc, char **argv )
|
|||||||
|
|
||||||
|
|
||||||
case aSignEncr: /* sign and encrypt the given file */
|
case aSignEncr: /* sign and encrypt the given file */
|
||||||
|
log_fatal("signing and encryption is not yet implemented\n");
|
||||||
usage(1); /* FIXME */
|
usage(1); /* FIXME */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
53
g10/keygen.c
53
g10/keygen.c
@ -39,17 +39,6 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
answer_is_yes( const char *s )
|
|
||||||
{
|
|
||||||
if( !stricmp(s, "yes") )
|
|
||||||
return 1;
|
|
||||||
if( *s == 'y' && !s[1] )
|
|
||||||
return 1;
|
|
||||||
if( *s == 'Y' && !s[1] )
|
|
||||||
return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static u16
|
static u16
|
||||||
@ -356,7 +345,7 @@ generate_keypair()
|
|||||||
else if( algo == 3 ) {
|
else if( algo == 3 ) {
|
||||||
algo = PUBKEY_ALGO_DSA;
|
algo = PUBKEY_ALGO_DSA;
|
||||||
algo_name = "DSA";
|
algo_name = "DSA";
|
||||||
break;
|
tty_printf("Sorry; DSA is not yet supported.\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -380,8 +369,8 @@ generate_keypair()
|
|||||||
#endif
|
#endif
|
||||||
if( algo == PUBKEY_ALGO_DSA && (nbits < 512 || nbits > 1024) )
|
if( algo == PUBKEY_ALGO_DSA && (nbits < 512 || nbits > 1024) )
|
||||||
tty_printf("DSA does only allow keysizes from 512 to 1024\n");
|
tty_printf("DSA does only allow keysizes from 512 to 1024\n");
|
||||||
else if( nbits < 128 ) /* FIXME: change this to 768 */
|
else if( nbits < 768 )
|
||||||
tty_printf("keysize too small; please select a larger one\n");
|
tty_printf("keysize too small; 768 is smallest value allowed.\n");
|
||||||
else if( nbits > 2048 ) {
|
else if( nbits > 2048 ) {
|
||||||
tty_printf("Keysizes larger than 2048 are not suggested, because "
|
tty_printf("Keysizes larger than 2048 are not suggested, because "
|
||||||
"computations take REALLY long!\n");
|
"computations take REALLY long!\n");
|
||||||
@ -441,20 +430,28 @@ generate_keypair()
|
|||||||
tty_printf( "You need a Passphrase to protect your secret key.\n\n" );
|
tty_printf( "You need a Passphrase to protect your secret key.\n\n" );
|
||||||
|
|
||||||
dek = m_alloc_secure( sizeof *dek );
|
dek = m_alloc_secure( sizeof *dek );
|
||||||
dek->algo = CIPHER_ALGO_BLOWFISH;
|
for(;;) {
|
||||||
rc = make_dek_from_passphrase( dek , 2 );
|
dek->algo = CIPHER_ALGO_BLOWFISH;
|
||||||
if( rc == -1 ) {
|
rc = make_dek_from_passphrase( dek , 2 );
|
||||||
m_free(dek); dek = NULL;
|
if( rc == -1 ) {
|
||||||
tty_printf(
|
m_free(dek); dek = NULL;
|
||||||
|
tty_printf(
|
||||||
"You don't what a passphrase - this is probably a *bad* idea!\n"
|
"You don't what a passphrase - this is probably a *bad* idea!\n"
|
||||||
"I will do it anyway. You can change your passphrase at anytime,\n"
|
"I will do it anyway. You can change your passphrase at anytime,\n"
|
||||||
"using this program with the option \"--change-passphrase\"\n\n" );
|
"using this program with the option \"--change-passphrase\"\n\n" );
|
||||||
}
|
break;
|
||||||
else if( rc ) {
|
}
|
||||||
m_free(dek); dek = NULL;
|
else if( rc == G10ERR_PASSPHRASE ) {
|
||||||
m_free(uid);
|
tty_printf("passphrase not correctly repeated; try again.\n");
|
||||||
log_error("Error getting the passphrase: %s\n", g10_errstr(rc) );
|
}
|
||||||
return;
|
else if( rc ) {
|
||||||
|
m_free(dek); dek = NULL;
|
||||||
|
m_free(uid);
|
||||||
|
log_error("Error getting the passphrase: %s\n", g10_errstr(rc) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break; /* okay */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -474,6 +471,12 @@ generate_keypair()
|
|||||||
pub_root = make_comment_node("#created by G10 pre-release " VERSION );
|
pub_root = make_comment_node("#created by G10 pre-release " VERSION );
|
||||||
sec_root = make_comment_node("#created by G10 pre-release " VERSION );
|
sec_root = make_comment_node("#created by G10 pre-release " VERSION );
|
||||||
|
|
||||||
|
tty_printf(
|
||||||
|
"We need to generate a lot of random bytes. It is a good idea to perform\n"
|
||||||
|
"some other action (work in another window, move the mouse, utilize the\n"
|
||||||
|
"network and the disks) during the prime generation; this gives the random\n"
|
||||||
|
"number generator a better chance to gain enough entropy.\n" );
|
||||||
|
|
||||||
if( algo == PUBKEY_ALGO_ELGAMAL )
|
if( algo == PUBKEY_ALGO_ELGAMAL )
|
||||||
rc = gen_elg(nbits, pub_root, sec_root, dek, &skc );
|
rc = gen_elg(nbits, pub_root, sec_root, dek, &skc );
|
||||||
#ifdef HAVE_RSA_CIPHER
|
#ifdef HAVE_RSA_CIPHER
|
||||||
|
@ -37,6 +37,9 @@ int encode_crypt( const char *filename, STRLIST remusr );
|
|||||||
int sign_file( const char *filename, int detached, STRLIST locusr );
|
int sign_file( const char *filename, int detached, STRLIST locusr );
|
||||||
int sign_key( const char *username, STRLIST locusr );
|
int sign_key( const char *username, STRLIST locusr );
|
||||||
|
|
||||||
|
/*-- sig-check.c --*/
|
||||||
|
int check_key_signature( KBNODE root, KBNODE node );
|
||||||
|
|
||||||
/*-- keygen.c --*/
|
/*-- keygen.c --*/
|
||||||
void generate_keypair(void);
|
void generate_keypair(void);
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ open_outfile( const char *iname )
|
|||||||
IOBUF a = NULL;
|
IOBUF a = NULL;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if( (!iname && !opt.outfile) || opt.outfile_is_stdout ) {
|
if( !iname && !opt.outfile ) {
|
||||||
if( !(a = iobuf_create(NULL)) )
|
if( !(a = iobuf_create(NULL)) )
|
||||||
log_error("can't open [stdout]: %s\n", strerror(errno) );
|
log_error("can't open [stdout]: %s\n", strerror(errno) );
|
||||||
else if( opt.verbose )
|
else if( opt.verbose )
|
||||||
|
@ -26,7 +26,7 @@ struct {
|
|||||||
int armor;
|
int armor;
|
||||||
int compress;
|
int compress;
|
||||||
char *outfile;
|
char *outfile;
|
||||||
int outfile_is_stdout;
|
int reserved0;
|
||||||
int batch; /* run in batch mode */
|
int batch; /* run in batch mode */
|
||||||
int answer_yes; /* answer yes on most questions */
|
int answer_yes; /* answer yes on most questions */
|
||||||
int answer_no; /* answer no on most questions */
|
int answer_no; /* answer no on most questions */
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "ttyio.h"
|
#include "ttyio.h"
|
||||||
#include "cipher.h"
|
#include "cipher.h"
|
||||||
|
#include "keydb.h"
|
||||||
|
|
||||||
|
|
||||||
static int hash_passphrase( DEK *dek, char *pw );
|
static int hash_passphrase( DEK *dek, char *pw );
|
||||||
@ -44,8 +45,14 @@ get_passphrase_hash( u32 *keyid, char *text )
|
|||||||
DEK *dek;
|
DEK *dek;
|
||||||
|
|
||||||
if( keyid ) {
|
if( keyid ) {
|
||||||
|
char *ustr;
|
||||||
tty_printf("\nNeed a pass phrase to unlock the secret key!\n");
|
tty_printf("\nNeed a pass phrase to unlock the secret key!\n");
|
||||||
tty_printf("KeyID: %08lX\n\n", keyid[1] );
|
tty_printf("KeyID: " );
|
||||||
|
ustr = get_user_id_string( keyid );
|
||||||
|
tty_print_string( ustr, strlen(ustr) );
|
||||||
|
m_free(ustr);
|
||||||
|
tty_printf("\n\n");
|
||||||
|
|
||||||
}
|
}
|
||||||
if( keyid && (p=getenv("G10PASSPHRASE")) ) {
|
if( keyid && (p=getenv("G10PASSPHRASE")) ) {
|
||||||
pw = m_alloc_secure(strlen(p)+1);
|
pw = m_alloc_secure(strlen(p)+1);
|
||||||
|
@ -56,13 +56,8 @@ handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx )
|
|||||||
fname[pt->namelen] = 0;
|
fname[pt->namelen] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !*fname ) { /* no filename given */
|
if( !*fname ) { /* no filename given; write to stdout */
|
||||||
if( opt.outfile_is_stdout )
|
fp = stdout;
|
||||||
fp = stdout;
|
|
||||||
else {
|
|
||||||
log_error("no outputfile given\n");
|
|
||||||
goto leave;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if( overwrite_filep( fname ) )
|
else if( overwrite_filep( fname ) )
|
||||||
goto leave;
|
goto leave;
|
||||||
|
@ -558,7 +558,7 @@ keyring_delete( KBPOS *kbpos )
|
|||||||
}
|
}
|
||||||
|
|
||||||
len = kbpos->length;
|
len = kbpos->length;
|
||||||
log_debug("writing a dummy packet of length %lu\n", (ulong)len);
|
/*log_debug("writing a dummy packet of length %lu\n", (ulong)len);*/
|
||||||
|
|
||||||
if( len < 2 )
|
if( len < 2 )
|
||||||
log_bug(NULL);
|
log_bug(NULL);
|
||||||
|
@ -198,8 +198,8 @@ signature_check( PKT_signature *sig, MD_HANDLE *digest )
|
|||||||
}
|
}
|
||||||
#endif/*HAVE_RSA_CIPHER*/
|
#endif/*HAVE_RSA_CIPHER*/
|
||||||
else {
|
else {
|
||||||
log_debug("signature_check: unsupported pubkey algo %d\n",
|
/*log_debug("signature_check: unsupported pubkey algo %d\n",
|
||||||
pkc->pubkey_algo );
|
pkc->pubkey_algo );*/
|
||||||
rc = G10ERR_PUBKEY_ALGO;
|
rc = G10ERR_PUBKEY_ALGO;
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
@ -219,13 +219,46 @@ signature_check( PKT_signature *sig, MD_HANDLE *digest )
|
|||||||
int
|
int
|
||||||
check_key_signature( KBNODE root, KBNODE node )
|
check_key_signature( KBNODE root, KBNODE node )
|
||||||
{
|
{
|
||||||
|
KBNODE unode;
|
||||||
|
MD_HANDLE *md;
|
||||||
|
PKT_public_cert *pkc;
|
||||||
|
PKT_signature *sig;
|
||||||
|
int algo;
|
||||||
|
int rc;
|
||||||
|
|
||||||
assert( node->pkt->pkttype == PKT_SIGNATURE );
|
assert( node->pkt->pkttype == PKT_SIGNATURE );
|
||||||
assert( (node->pkt->pkt.signature->sig_class&~3) == 0x10 );
|
assert( (node->pkt->pkt.signature->sig_class&~3) == 0x10 );
|
||||||
assert( root->pkt->pkttype == PKT_PUBLIC_CERT );
|
assert( root->pkt->pkttype == PKT_PUBLIC_CERT );
|
||||||
|
|
||||||
/*FIXME!!!!!!*/
|
pkc = root->pkt->pkt.public_cert;
|
||||||
|
sig = node->pkt->pkt.signature;
|
||||||
|
|
||||||
return 0;
|
if( sig->pubkey_algo == PUBKEY_ALGO_ELGAMAL )
|
||||||
|
algo = sig->d.elg.digest_algo;
|
||||||
|
else if(sig->pubkey_algo == PUBKEY_ALGO_RSA )
|
||||||
|
algo = sig->d.rsa.digest_algo;
|
||||||
|
else
|
||||||
|
return G10ERR_PUBKEY_ALGO;
|
||||||
|
if( (rc=md_okay(algo)) )
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
unode = find_kbparent( root, node );
|
||||||
|
|
||||||
|
if( unode && unode->pkt->pkttype == PKT_USER_ID ) {
|
||||||
|
PKT_user_id *uid = unode->pkt->pkt.user_id;
|
||||||
|
|
||||||
|
md = md_open( algo, 0 );
|
||||||
|
hash_public_cert( md, pkc );
|
||||||
|
md_write( md, uid->name, uid->len );
|
||||||
|
rc = signature_check( sig, md );
|
||||||
|
md_close(md);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
log_error("no user id for key signature packet\n");
|
||||||
|
rc = G10ERR_SIG_CLASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -84,6 +84,7 @@ char *make_filename( const char *first_part, ... );
|
|||||||
/*-- miscutil.c --*/
|
/*-- miscutil.c --*/
|
||||||
u32 make_timestamp(void);
|
u32 make_timestamp(void);
|
||||||
void print_string( FILE *fp, byte *p, size_t n );
|
void print_string( FILE *fp, byte *p, size_t n );
|
||||||
|
int answer_is_yes( const char *s );
|
||||||
|
|
||||||
/*-- strgutil.c --*/
|
/*-- strgutil.c --*/
|
||||||
void free_strlist( STRLIST sl );
|
void free_strlist( STRLIST sl );
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
@ -52,3 +53,15 @@ print_string( FILE *fp, byte *p, size_t n )
|
|||||||
putc(*p, fp);
|
putc(*p, fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
answer_is_yes( const char *s )
|
||||||
|
{
|
||||||
|
if( !stricmp(s, "yes") )
|
||||||
|
return 1;
|
||||||
|
if( *s == 'y' && !s[1] )
|
||||||
|
return 1;
|
||||||
|
if( *s == 'Y' && !s[1] )
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user