/********************************************************************* * pgp_write.cc -- This writes out a single PGP packet of your choice * with the supplied information (ex. public key certificates, secret * keys, userid packets...) Written PGP packets can then be either used * alone or `cat`ed together for use with PGP. * * `./pgp_write -?` for explanation of options. * * Requires a large integer library (such as GMP) and a class named * "Integer" that supports it (+, -, *, etc.) in the file. * * Compile: * g++ -o pgp_write pgp_write.cc libgmp.a * Invoke: * ./pgp_write * Changelog: * 971024: Created - Paul Herman *****************************************************************/ #include #include #include #include // time stuff #include // umask #include "Integer.h" #define MAX_PACKET_SIZE 16384 // Never this big, but just in case /******** Flags in the first "CTB" byte ********/ #define CTB_ALWAYS (1<<7) #define CTB_PUB_KEY (0x01<<2) /* Public Key Encrypted x */ #define CTB_SEC_KEY (0x02<<2) /* Secret Key Signature x */ #define CTB_SEC_CER (0x05<<2) /* Secret Key info x */ #define CTB_PUB_CER (0x06<<2) /* Public Key info x */ #define CTB_CMP_DAT (0x08<<2) /* Compressed Data */ #define CTB_CNV_ENC (0x09<<2) /* Conventionally Encrypted Data */ #define CTB_RAW_TXT (0x0b<<2) /* Raw Plain Text */ #define CTB_KEY_TST (0x0c<<2) /* Key Trust Packet */ #define CTB_USR_IDN (0x0d<<2) /* User ID Packet x */ #define CTB_COM_MNT (0x0e<<2) /* Comment Packet */ #define CTB_LEN_8 0x00 #define CTB_LEN_16 0x01 #define CTB_LEN_32 0x02 #define CTB_LEN_UNK 0x03 /********* Types of Algorithms ********/ #define ALG_RSA 1 #define ALG_UNK 0 #define ALG_MD5 1 /********* Ways to hide secret exponents ********/ #define ENC_IDEA 1 #define ENC_NONE 0 /***** Few global variables *****/ int verbose = 0; int stdoutput = 0; /* default values */ int PGP_version = 3; int PGP_validity = 0; int PGP_algorithm = ALG_RSA; int PGP_secret_encrypt = ENC_NONE; unsigned int PGP_64bit_id[2] = { 0x12345678, 0x98765432 }; int PGP_MDx_len = 5; int PGP_sig_classification = 1; int PGP_digest_algorithm = ALG_MD5; char user_id[256] = "fred"; Integer public_modulus = 0; Integer public_exponent = 0; Integer secret_exponent = 0; Integer secret_p = 0; Integer secret_q = 0; Integer secret_u = 0; Integer encrypted_IDEA_key = 0; Integer sig_digest = 5; time_t tme; /**** int_handler() - tidy up and exit ****/ static void int_handler(int unused) { printf("Caught an interrupt! Exiting...\n"); exit(1); } void Panic(char *s) { fprintf(stderr, "%s", s); exit(1); } void write_buff_to_file(char *filename, unsigned char *buff, int len) { FILE *fp; int i; if (stdoutput) { for (i=0; i> 8) & 0xff; *p++ = bits & 0xff; tmp = 256; for (i=bytes-1; i>-1; i--) { tmp2 = intgr & (tmp-1); p[i] = ((int) (tmp2/ (tmp/256))) & 0x000000ff ; tmp *= 256; } return bytes+2; } void store_len(unsigned char *buff, int len) { if ( (*buff & 0x03) == CTB_LEN_8) { buff[1] = len & 0x000000ff; } if ( (*buff & 0x03) == CTB_LEN_16) { buff[1] = (len >> 8) & 0x000000ff; buff[2] = len & 0x000000ff; } if ( (*buff & 0x03) == CTB_LEN_32) { buff[1] = (len >> 24) & 0x000000ff; buff[2] = (len >> 16) & 0x000000ff; buff[3] = (len >> 8) & 0x000000ff; buff[4] = len & 0x000000ff; } } void stamp_time(unsigned char *buff) { buff[0] = (tme & 0xff000000) >> 24; buff[1] = (tme & 0x00ff0000) >> 16; buff[2] = (tme & 0x0000ff00) >> 8; buff[3] = tme & 0x000000ff; } void stamp_64bits(unsigned char *buff, unsigned int *data) { buff[0] = (data[0] & 0xff000000) >> 24; buff[1] = (data[0] & 0x00ff0000) >> 16; buff[2] = (data[0] & 0x0000ff00) >> 8; buff[3] = data[0] & 0x000000ff; buff[4] = (data[1] & 0xff000000) >> 24; buff[5] = (data[1] & 0x00ff0000) >> 16; buff[6] = (data[1] & 0x0000ff00) >> 8; buff[7] = data[1] & 0x000000ff; } /******************************************************************/ void write_rsa_packet(char *filename) { unsigned char *buff, *ptr; unsigned int bt, len; buff = (unsigned char *) malloc(MAX_PACKET_SIZE); if (buff == 0) Panic("Not enough memory!\n"); ptr = buff; len = 0; /* CTB byte */ bt = CTB_ALWAYS | CTB_PUB_KEY | CTB_LEN_16; *ptr++ = bt; /* Length of Packet */ *ptr++ = 0; *ptr++ = 0; /* will write later */ /* Version Byte */ *ptr++ = PGP_version; len++; /* 64-bit ID */ stamp_64bits(ptr, PGP_64bit_id); ptr += 2*sizeof(int); len += 2*sizeof(int); /* PGP Algorithm RSA=1, ??=Other */ *ptr++ = PGP_algorithm; len++; /* Public Modulus, N */ bt = write_mpi(encrypted_IDEA_key, ptr); ptr += bt; len += bt; store_len(buff, len); write_buff_to_file(filename, buff, ptr-buff); free(buff); } void write_sig_packet(char *filename) { unsigned char *buff, *ptr; unsigned int bt, len; buff = (unsigned char *) malloc(MAX_PACKET_SIZE); if (buff == 0) Panic("Not enough memory!\n"); ptr = buff; len = 0; /* CTB byte */ bt = CTB_ALWAYS | CTB_SEC_KEY | CTB_LEN_16; *ptr++ = bt; /* Length of Packet */ *ptr++ = 0; *ptr++ = 0; /* will write later */ /* Version Byte */ *ptr++ = PGP_version; len++; /* Digest length (usually 5, as in "MD5") */ *ptr++ = PGP_MDx_len; len++; /* Signature Classification Field */ *ptr++ = PGP_sig_classification; len++; /* Time Stamp */ stamp_time(ptr); ptr += sizeof(time_t); len += sizeof(time_t); /* 64-bit ID */ stamp_64bits(ptr, PGP_64bit_id); ptr += 2*sizeof(int); len += 2*sizeof(int); /* PGP Algorithm RSA=1, ??=Other */ *ptr++ = PGP_algorithm; len++; /* Digest Algorithm MD5=1, ??=Other */ *ptr++ = PGP_digest_algorithm; len++; /* First two bytes of digest */ *ptr++ = 0; *ptr++ = 0; len += 2; /* RSA encrypted digest, in MPI form */ bt = write_mpi(sig_digest, ptr); ptr += bt; len += bt; store_len(buff, len); write_buff_to_file(filename, buff, ptr-buff); free(buff); } void write_secret_key(char *filename) { unsigned char *buff, *ptr; unsigned int bt, len; buff = (unsigned char *) malloc(MAX_PACKET_SIZE); if (buff == 0) Panic("Not enough memory!\n"); ptr = buff; len = 0; /* CTB byte */ bt = CTB_ALWAYS | CTB_SEC_CER | CTB_LEN_16; *ptr++ = bt; /* Length of Packet */ *ptr++ = 0; *ptr++ = 0; /* will write later */ /* Version Byte */ *ptr++ = PGP_version; len++; /* Time Stamp */ stamp_time(ptr); ptr += sizeof(time_t); len += sizeof(time_t); /* Validity in days */ *ptr++ = (PGP_validity >> 8) & 0xff; *ptr++ = PGP_validity & 0xff; len+=2; /* PGP Algorithm RSA=1, ??=Other */ *ptr++ = PGP_algorithm; len++; /* Public Modulus, N */ bt = write_mpi(public_modulus, ptr); ptr += bt; len += bt; /* Public Exponent, E */ bt = write_mpi(public_exponent, ptr); ptr += bt; len += bt; /* Secret Key hiding alg. Unencrypted=0, IDEA=1 */ *ptr++ = PGP_secret_encrypt; len++; /* Secret Exponent, D */ bt = write_mpi(secret_exponent, ptr); ptr += bt; len += bt; /* Secret Factor, P */ bt = write_mpi(secret_p, ptr); ptr += bt; len += bt; /* Secret Factor, Q */ bt = write_mpi(secret_q, ptr); ptr += bt; len += bt; /* Secret Multiplicative Inverse, U */ bt = write_mpi(secret_u, ptr); ptr += bt; len += bt; /* 16-bit Checksum of all secret bytes */ *ptr++ = 0; *ptr++ = 0; len += 2; /* Not right! FIX!!!! */ store_len(buff, len); write_buff_to_file(filename, buff, ptr-buff); free(buff); } void write_public_key(char *filename) { unsigned char *buff, *ptr; unsigned int bt, len; buff = (unsigned char *) malloc(MAX_PACKET_SIZE); if (buff == 0) Panic("Not enough memory!\n"); ptr = buff; len = 0; /* CTB byte */ bt = CTB_ALWAYS | CTB_PUB_CER | CTB_LEN_16; *ptr++ = bt; /* Length of Packet */ *ptr++ = 0; *ptr++ = 0; /* will write later */ /* Version Byte */ *ptr++ = PGP_version; len++; /* Time Stamp */ stamp_time(ptr); ptr += sizeof(time_t); len += sizeof(time_t); /* Validity in days */ *ptr++ = (PGP_validity >> 8) & 0xff; *ptr++ = PGP_validity & 0xff; len+=2; /* PGP Algorithm RSA=1, ??=Other */ *ptr++ = PGP_algorithm; len++; /* Public Modulus, N */ bt = write_mpi(public_modulus, ptr); ptr += bt; len += bt; /* Public Exponent, E */ bt = write_mpi(public_exponent, ptr); ptr += bt; len += bt; store_len(buff, len); write_buff_to_file(filename, buff, ptr-buff); free(buff); } void write_user_id(char *filename) { unsigned char *buff, *ptr; unsigned int bt, len; buff = (unsigned char *) malloc(MAX_PACKET_SIZE); if (buff == 0) Panic("Not enough memory!\n"); ptr = buff; len = 0; /* CTB byte */ /* Want to or (|) #defines */ bt = CTB_ALWAYS | CTB_USR_IDN | CTB_LEN_8; *ptr++ = bt; /* Length of Packet */ *ptr++ = 0; /* will write later */ sprintf((char *)ptr, "%s", user_id); len += strlen((char *)ptr); ptr += strlen((char *)ptr); /* Finally write the len */ buff[1] = len & 0x000000ff; write_buff_to_file(filename, buff, ptr-buff); free(buff); } void write_comment_packet(char *filename) { unsigned char *buff, *ptr; unsigned int bt, len; buff = (unsigned char *) malloc(MAX_PACKET_SIZE); if (buff == 0) Panic("Not enough memory!\n"); ptr = buff; len = 0; /* CTB byte */ /* Want to or (|) #defines */ bt = CTB_ALWAYS | CTB_COM_MNT | CTB_LEN_8; *ptr++ = bt; /* Length of Packet */ *ptr++ = 0; /* will write later */ sprintf((char *)ptr, "%s", user_id); len += strlen((char *)ptr); ptr += strlen((char *)ptr); /* Finally write the len */ buff[1] = len & 0x000000ff; write_buff_to_file(filename, buff, ptr-buff); free(buff); } int are_equal(char *a, char *b) { int r=1, i=0; if (!*a && !*b) return 1; if (!*a) return 0; for (i=0; i