#include #include #include #include #include #include #include #include #include #include extern const char *__progname; /* MAXBLOCK can be anything above the encryption block size; making it larger will reduce the best-case expansion due to -stream. */ /* SLOP can be anything that is (a) at least one encryption block and (b) such that 7*SLOP is no smaller than the number of bits needed to represent the value of MAXBLOCK. Normally (a) is more stringent. :-) */ #define MAXBLOCK 8192 #define SLOP 8 #define MODE_NONE 0 #define MODE_E 1 #define MODE_D 2 #define MODE_KE 3 #define MODE_KD 4 #define MODE_KH 5 #define MODE_GENVEC 6 #define MODE_BLOCK 7 static int opmode = MODE_NONE; static const char *keyphrase = 0; static const char *blockdata = 0; #define KS_PHRASE 1 #define KS_SCHED 2 #define KS_HASH 3 static int keystyle = KS_PHRASE; static const char *ivarg = 0; #define MODE_ECB 1 #define MODE_CBC 2 #define MODE_CFB 3 #define MODE_OFB 4 static int ciphermode = MODE_CBC; static int streaming = 0; static const char *keyfdarg = 0; static int debugging = 0; static unsigned char iv[8]; static unsigned char keyhash[16]; static IDEA_KEY k; static unsigned char stealbuf[8]; static void *deconst(const void *cp) { void *p; bcopy(&cp,&p,sizeof(void *)); return(p); } static void copy_sensitive(char *from, const char **to_p) { int l; char *s; l = strlen(from); s = malloc(l+1); if (! s) { fprintf(stderr,"%s: out of memory\n",__progname); exit(1); } strcpy(s,from); bzero(from,l); if (*to_p) free(deconst(to_p)); *to_p = s; } static void handleargs(int ac, char **av) { int skip; int errs; skip = 0; errs = 0; for (ac--,av++;ac;ac--,av++) { if (skip > 0) { skip --; continue; } if (**av != '-') { fprintf(stderr,"%s: unrecognized argument `%s'\n",__progname,*av); errs ++; continue; } if (0) { needarg:; fprintf(stderr,"%s: %s needs a following argument\n",__progname,*av); errs ++; continue; } #define WANTARG() do { if (++skip >= ac) goto needarg; } while (0) if (!strcmp(*av,"-e")) { WANTARG(); opmode = MODE_E; copy_sensitive(av[skip],&keyphrase); continue; } if (!strcmp(*av,"-d")) { WANTARG(); opmode = MODE_D; copy_sensitive(av[skip],&keyphrase); continue; } if (!strcmp(*av,"-ke")) { WANTARG(); opmode = MODE_KE; copy_sensitive(av[skip],&keyphrase); continue; } if (!strcmp(*av,"-kd")) { WANTARG(); opmode = MODE_KD; copy_sensitive(av[skip],&keyphrase); continue; } if (!strcmp(*av,"-kh")) { WANTARG(); opmode = MODE_KH; copy_sensitive(av[skip],&keyphrase); continue; } if (!strcmp(*av,"-genvec")) { opmode = MODE_GENVEC; continue; } if (!strcmp(*av,"-block")) { WANTARG(); opmode = MODE_BLOCK; keystyle = KS_SCHED; copy_sensitive(av[skip],&keyphrase); WANTARG(); copy_sensitive(av[skip],&blockdata); continue; } if (!strcmp(*av,"-keysched")) { keystyle = KS_SCHED; continue; } if (!strcmp(*av,"-keyhash")) { keystyle = KS_HASH; continue; } if (!strcmp(*av,"-keyphrase")) { keystyle = KS_PHRASE; continue; } if (!strcmp(*av,"-iv")) { WANTARG(); copy_sensitive(av[skip],&ivarg); continue; } if (!strcmp(*av,"-ecb")) { ciphermode = MODE_ECB; continue; } if (!strcmp(*av,"-cbc")) { ciphermode = MODE_CBC; continue; } if (!strcmp(*av,"-cfb")) { ciphermode = MODE_CFB; continue; } if (!strcmp(*av,"-ofb")) { ciphermode = MODE_OFB; continue; } if (!strcmp(*av,"-stream")) { streaming = 1; continue; } if (!strcmp(*av,"-nostream")) { streaming = 1; continue; } if (!strcmp(*av,"-readkey")) { WANTARG(); keyfdarg = av[skip]; continue; } if (!strcmp(*av,"-debug")) { debugging = 1; continue; } #undef WANTARG fprintf(stderr,"%s: unrecognized option `%s'\n",__progname,*av); errs ++; } if (errs) exit(1); } static void no_cores_please(void) { struct rlimit rl; rl.rlim_cur = 0; rl.rlim_max = 0; setrlimit(RLIMIT_CORE,&rl); } static int hdigval(char c) { switch (c) { case '0': return(0); break; case '1': return(1); break; case '2': return(2); break; case '3': return(3); break; case '4': return(4); break; case '5': return(5); break; case '6': return(6); break; case '7': return(7); break; case '8': return(8); break; case '9': return(9); break; case 'a': case 'A': return(10); break; case 'b': case 'B': return(11); break; case 'c': case 'C': return(12); break; case 'd': case 'D': return(13); break; case 'e': case 'E': return(14); break; case 'f': case 'F': return(15); break; } return(-1); } static const char *process_hexarg(const char *arg, void *buf, int nb) { const char *ap; unsigned char *bp; int nib_h; int nib_l; if (! arg) { fprintf(stderr,"%s: nil argument to process_hexarg\n",__progname); abort(); } ap = arg; bp = buf; for (;nb>0;nb--) { nib_h = hdigval(*ap++); if (nib_h < 0) goto err; nib_l = hdigval(*ap++); if (nib_l < 0) goto err; *bp++ = (nib_h << 4) | nib_l; } return(0); err:; if (ap[-1] == '\0') return("too short"); return("invalid hex character"); } static void get_iv(void) { struct timeval tv; char buf[256]; int i; long int l; void *m; if (ivarg) { const char *why; why = process_hexarg(ivarg,&iv[0],8); if (! why) return; fprintf(stderr,"%s: invalid IV argument `%s' (%s)\n",__progname,ivarg,why); exit(1); } m = md5_init(); md5_process_bytes(m,&m,sizeof(m)); i = getpid(); md5_process_bytes(m,&i,sizeof(i)); l = gethostid(); md5_process_bytes(m,&l,sizeof(l)); i = gethostname(&buf[0],sizeof(buf)); md5_process_bytes(m,&i,sizeof(i)); md5_process_bytes(m,&buf[0],sizeof(buf)); gettimeofday(&tv,0); md5_process_bytes(m,&tv,sizeof(tv)); md5_result(m,&buf[0]); bcopy(&buf[0],&iv[0],8); } static int get_key_fd(void) { int fd; char *ep; fd = strtol(keyfdarg,&ep,0); if (*ep || (ep == keyfdarg) || (fd < 0)) { fprintf(stderr,"%s: invalid key file descriptor number `%s'\n",__progname,keyfdarg); exit(1); } if (fcntl(fd,F_GETFD,0) < 0) { if (errno == EBADF) { fprintf(stderr,"%s: key file descriptor %d isn't open\n",__progname,fd); exit(1); } else { fprintf(stderr,"%s: fcntl key file descriptor %d: %s (please report this; it \"can't happen\"!)\n",__progname,fd,strerror(errno)); exit(1); } } return(fd); } static void keydata_read_stdin(char *cp) { int rv; rv = read(0,cp,1); switch (rv) { case -1: fprintf(stderr,"%s: error reading key data: %s\n",__progname,strerror(errno)); exit(1); break; case 0: fprintf(stderr,"%s: unexpected EOF reading key data\n",__progname); exit(1); break; case 1: break; default: fprintf(stderr,"%s: unexpected return %d from key data read (please report this; it \"can't happen\")\n",__progname,rv); exit(1); break; } } static void read_fd_hex(void *buf, int nb) { int fd; unsigned char *bp; int nib_h; int nib_l; char ch; int ich; FILE *f; fd = get_key_fd(); bp = buf; nib_h = -1; if (fd != 0) f = fdopen(fd,"r"); while (1) { if (fd == 0) { keydata_read_stdin(&ch); if (nb < 1) { if (ch == '\n') return; if (nb == 0) fprintf(stderr,"%s: junk ignored after key data on stdin\n",__progname); nb = -1; continue; } if (ch == '\n') { fprintf(stderr,"%s: invalid key data on stdin (too short)\n",__progname); exit(1); } } else { if (nb < 1) { fclose(f); return; } ich = getc(f); if (ich == EOF) { if (ferror(f)) { fprintf(stderr,"%s: error reading key data: %s\n",__progname,strerror(errno)); } else { fprintf(stderr,"%s: unexpected EOF reading key data\n",__progname); } exit(1); } ch = ich; } if (nib_h < 0) { nib_h = hdigval(ch); if (nib_h < 0) { fprintf(stderr,"%s: invalid key data (invalid hex character)\n",__progname); exit(1); } continue; } else { nib_l = hdigval(ch); if (nib_l < 0) { fprintf(stderr,"%s: invalid key data (invalid hex character)\n",__progname); exit(1); } *bp++ = (nib_h << 4) + nib_l; nb --; } } } static void hash_fd_phrase(void) { void *m; int fd; fd = get_key_fd(); m = md5_init(); if (fd == 0) { while (1) { char ch; keydata_read_stdin(&ch); if (ch == '\n') break; md5_process_bytes(m,&ch,1); } } else { char buf[8192]; int rv; while (1) { rv = read(fd,&buf[0],sizeof(buf)); if (fd < 0) { fprintf(stderr,"%s: error reading key data: %s\n",__progname,strerror(errno)); exit(1); } if (rv == 0) break; md5_process_bytes(m,&buf[0],rv); } } md5_result(m,&keyhash[0]); } static void get_keyhash(void) { switch (keystyle) { case KS_SCHED: fprintf(stderr,"%s: can't use -keysched with this operation\n",__progname); exit(1); break; case KS_HASH: if (keyfdarg) { read_fd_hex(&keyhash[0],16); } else { const char *why; why = process_hexarg(keyphrase,&keyhash[0],16); if (! why) return; fprintf(stderr,"%s: invalid key argument `%s' (%s)\n",__progname,keyphrase,why); exit(1); } break; case KS_PHRASE: if (keyfdarg) { hash_fd_phrase(); } else { void *m; m = md5_init(); md5_process_bytes(m,keyphrase,strlen(keyphrase)); md5_result(m,&keyhash[0]); } break; default: fprintf(stderr,"%s: impossible key mode %d\n",__progname,keystyle); abort(); break; } } static void get_keysched(int decrypt) { switch (keystyle) { case KS_SCHED: if (keyfdarg) { read_fd_hex(&k.Z[0],104); } else { const char *why; why = process_hexarg(keyphrase,&k.Z[0],104); if (! why) return; fprintf(stderr,"%s: invalid key argument `%s' (%s)\n",__progname,keyphrase,why); exit(1); } break; default: get_keyhash(); if (decrypt) idea_setkey_d(&keyhash[0],&k); else idea_setkey_e(&keyhash[0],&k); break; } } static void print_hex(const void *buf, int nb) { const unsigned char *bp; bp = buf; for (;nb>0;nb--) printf("%02x",*bp++); printf("\n"); } static void do_block(void) { const char *why; unsigned char blk[8]; why = process_hexarg(blockdata,&blk[0],8); idea_crypt(&blk[0],&k,&blk[0]); print_hex(&blk[0],8); } static void write_out(unsigned char *buf, int nb) { unsigned char *bp; int nw; bp = buf; while (nb > 0) { nw = write(1,bp,nb); if (nw < 0) { fprintf(stderr,"%s: output write error: %s\n",__progname,strerror(errno)); exit(1); } if (nw > nb) { fprintf(stderr,"%s: output wrote more than requested (please report this; it \"can't happen\")\n",__progname); fprintf(stderr,"%s: wanted %d did %d\n",__progname,nb,nw); abort(); } if (nw != nb) { fprintf(stderr,"%s: short output write: wanted %d did %d\n",__progname,nb,nw); fprintf(stderr,"%s: retrying remainder\n",__progname); } nb -= nw; bp += nw; } } static void do_ecb(void) { unsigned char buf[8192]; unsigned char *bp; int bf; int nr; bf = 0; while (1) { nr = read(0,&buf[bf],sizeof(buf)-bf); if (nr < 0) { fprintf(stderr,"%s: input read error: %s\n",__progname,strerror(errno)); exit(1); } if (nr == 0) { if (bf > 0) { fprintf(stderr,"%s: partial block at EOF ignored in ECB mode\n",__progname); } break; } nr += bf; bp = &buf[0]; for (;nr>=8;nr-=8,bp+=8) idea_crypt(bp,&k,bp); write_out(&buf[0],bp-&buf[0]); if (nr > 0) bcopy(bp,&buf[0],nr); bf = nr; } } static int Read(int fd, void *buf, int nb) { char *bp; int left; int did; bp = buf; left = nb; while (left > 0) { did = read(fd,bp,left); if (did < 0) { fprintf(stderr,"%s: input read error: %s\n",__progname,strerror(errno)); exit(1); } if (did == 0) return(nb-left); bp += did; left -= did; } return(nb); } static void read_data_block(unsigned char *buf) { int nr; nr = Read(0,buf,8); if (nr != 8) { fprintf(stderr,"%s: premature EOF reading ciphertext\n",__progname); exit(1); } } static void do_ofb(void) { unsigned char buf[8192]; unsigned char *bp; int nr; int io; io = 0; while (1) { nr = read(0,&buf[0],sizeof(buf)); if (nr < 0) { fprintf(stderr,"%s: input read error: %s\n",__progname,strerror(errno)); exit(1); } if (nr == 0) break; bp = &buf[0]; for (;nr>0;nr--) { if (io == 0) idea_crypt(&iv[0],&k,&iv[0]); *bp++ ^= iv[io]; io = (io + 1) & 7; } write_out(&buf[0],bp-&buf[0]); } } static void do_cfb(int decrypt) { unsigned char buf[8192]; unsigned char *bp; int nr; int io; io = 0; while (1) { nr = read(0,&buf[0],sizeof(buf)); if (nr < 0) { fprintf(stderr,"%s: input read error: %s\n",__progname,strerror(errno)); exit(1); } if (nr == 0) break; bp = &buf[0]; for (;nr>0;nr--) { if (io == 0) idea_crypt(&iv[0],&k,&iv[0]); if (decrypt) { register unsigned char ch; ch = *bp ^ iv[io]; iv[io] = *bp; *bp++ = ch; } else { register unsigned char ch; ch = *bp ^ iv[io]; *bp++ = ch; iv[io] = ch; } io = (io + 1) & 7; } write_out(&buf[0],bp-&buf[0]); } } static void do_cbc_block(int decrypt) { unsigned char buf[8192]; unsigned char *bp; unsigned char tmp[8]; int bf; int nr; int i; bf = 0; while (1) { nr = read(0,&buf[bf],sizeof(buf)-bf); if (nr < 0) { fprintf(stderr,"%s: input read error: %s\n",__progname,strerror(errno)); exit(1); } if (nr == 0) { if (decrypt) { if (bf == 0) { write_out(&stealbuf[0],8); } else { /* buf<0..bf-1> holds C[n]; iv holds C[n-1] */ /* stealbuf holds what we thought at the time was P[n-1], ie, D(C[n-1]) ^ C[n-2]. */ idea_crypt(&iv[0],&k,&tmp[0]); for (i=0;i<8;i++) stealbuf[i] ^= tmp[i]; for (i=0;i=8;nr-=8,bp+=8) { if (decrypt) { idea_crypt(bp,&k,&tmp[0]); for (i=0;i<8;i++) { register unsigned char ch; ch = bp[i]; bp[i] = stealbuf[i]; stealbuf[i] = iv[i] ^ tmp[i]; iv[i] = ch; } } else { for (i=0;i<8;i++) { tmp[i] = iv[i] ^ bp[i]; bp[i] = iv[i]; } idea_crypt(&tmp[0],&k,&iv[0]); } } write_out(&buf[0],bp-&buf[0]); if (nr > 0) bcopy(bp,&buf[0],nr); bf = nr; } } static int cbc_steal_start(void) { int n; unsigned char tmp1[8]; unsigned char tmp2[8]; int i; n = Read(0,&tmp1[0],8); switch (n) { case 0: return(0); break; case 8: idea_crypt(&tmp1[0],&k,&tmp2[0]); for (i=0;i<8;i++) { stealbuf[i] = iv[i] ^ tmp2[i]; iv[i] = tmp1[i]; } return(1); break; } idea_crypt(&iv[0],&k,&tmp2[0]); for (i=0;i>7;i>0;i>>=7) *--bp = (i & 0x7f) | 0x80; nr = (nr + (&buf[SLOP] - bp) + 7) & ~7; i = 0; for (;nr>0;nr-=8,bp+=8,i+=8) idea_crypt(bp,&k,&buf[i]); if (debugging) fprintf(stderr,"%s: CBC stream encoder: writing %d\n",__progname,i); write_out(&buf[0],i); } } static void do_cbc_stream_d(void) { unsigned char ibuf[8192]; unsigned char *ip; int ibf; unsigned char obuf[8192]; int oo; int inlen; int oblen; int nr; int i; ibf = 0; inlen = 1; oblen = 0; while (1) { if (debugging) fprintf(stderr,"%s: CBC stream decoder: ibf %d\n",__progname,ibf); nr = read(0,&ibuf[ibf],sizeof(ibuf)-ibf); if (nr < 0) { fprintf(stderr,"%s: input read error: %s\n",__progname,strerror(errno)); exit(1); } if (nr == 0) { if (ibf > 0) fprintf(stderr,"%s: warning: decryption error: EOF partway through a basic block\n",__progname); if (! inlen) fprintf(stderr,"%s: warning: decryption error: EOF partway through a data chunk\n",__progname); if (inlen && (oblen != 0)) fprintf(stderr,"%s: warning: decryption error: EOF partway through a chunk length\n",__progname); break; } if (debugging) fprintf(stderr,"%s: CBC stream decoder: read %d\n",__progname,nr); nr += ibf; ip = &ibuf[0]; while (nr >= 8) { if (inlen) { idea_crypt(ip,&k,&obuf[0]); for (i=0;inlen&&(i<8);i++) { oblen = (oblen << 7) | (obuf[i] & 0x7f); if (! (obuf[i] & 0x80)) inlen = 0; } if (debugging) fprintf(stderr,"%s: CBC stream decoder: inlen %d, oblen %d\n",__progname,inlen,oblen); if (! inlen) { if (i < 8) bcopy(&obuf[i],&obuf[0],8-i); oo = 8 - i; if (debugging) fprintf(stderr,"%s: CBC stream decoder: oo %d\n",__progname,oo); } } else { idea_crypt(ip,&k,&obuf[oo]); oo += 8; } if (!inlen && (oo >= oblen)) { write_out(&obuf[0],oblen); if (debugging) fprintf(stderr,"%s: CBC stream decoder: finished block\n",__progname); inlen = 1; oblen = 0; } nr -= 8; ip += 8; } if (!inlen && (oo > 0)) { write_out(&obuf[0],oo); oblen -= oo; if (debugging) fprintf(stderr,"%s: CBC stream decoder: writing partial block %d (oblen %d)\n",__progname,oo,oblen); oo = 0; } if (nr > 0) bcopy(ip,&ibuf[0],nr); ibf = nr; } } static void do_encrypt(void) { switch (ciphermode) { case MODE_ECB: get_keysched(0); do_ecb(); break; case MODE_CBC: get_keysched(0); if (streaming) { write_out(&iv[0],8); do_cbc_stream_e(); } else { do_cbc_block(0); } break; case MODE_CFB: get_keysched(0); write_out(&iv[0],8); do_cfb(0); break; case MODE_OFB: get_keysched(0); write_out(&iv[0],8); do_ofb(); break; default: fprintf(stderr,"%s: impossible cipher mode %d\n",__progname,ciphermode); abort(); break; } } static void do_decrypt(void) { switch (ciphermode) { case MODE_ECB: get_keysched(1); do_ecb(); break; case MODE_CBC: get_keysched(1); if (streaming) { read_data_block(&iv[0]); do_cbc_stream_d(); } else { read_data_block(&iv[0]); if (cbc_steal_start()) do_cbc_block(1); } break; case MODE_CFB: get_keysched(0); read_data_block(&iv[0]); do_cfb(1); break; case MODE_OFB: get_keysched(0); read_data_block(&iv[0]); do_ofb(); break; default: fprintf(stderr,"%s: impossible cipher mode %d\n",__progname,ciphermode); abort(); break; } } int main(int, char **); int main(int ac, char **av) { handleargs(ac,av); if (! debugging) no_cores_please(); switch (opmode) { case MODE_E: get_iv(); do_encrypt(); break; case MODE_D: do_decrypt(); break; case MODE_KE: get_keysched(0); print_hex(&k.Z[0],104); break; case MODE_KD: get_keysched(1); print_hex(&k.Z[0],104); break; case MODE_KH: get_keyhash(); print_hex(&keyhash[0],16); break; case MODE_GENVEC: get_iv(); print_hex(&iv[0],8); break; case MODE_BLOCK: if (keystyle != KS_SCHED) { fprintf(stderr,"%s: -block implies and requires -keysched\n",__progname); exit(1); } get_keysched(0); do_block(); break; default: fprintf(stderr,"%s: impossible operation mode %d\n",__progname,opmode); abort(); break; } exit(0); } #if 0 #define SLOP 8 #define MAXBLK 65536 static IDEA_KEY k; static unsigned char keyhash[16]; static unsigned char buf[SLOP+MAXBLK+SLOP]; static unsigned char fb[8]; static unsigned char ctmp[8]; static char nulchar = '\0'; static void usage(void) __attribute__ ((__noreturn__)); static void usage(void) { fprintf(stderr,"Usage: %s -e|-d key\n",__progname); fprintf(stderr," or %s -ev key iv\n",__progname); fprintf(stderr," or %s -ke|-kd key\n",__progname); fprintf(stderr," or %s -te|-td|-t keyblk datablk\n",__progname); fprintf(stderr," or %s -iv\n",__progname); exit(1); } static void Write(const void *buf, int nb) { int n; n = write(1,buf,nb); if (n < 0) { fprintf(stderr,"%s: output write error: %s\n",__progname,strerror(errno)); exit(1); } if (n != nb) { fprintf(stderr,"%s: output write error: tried %d, did %d\n",__progname,nb,n); exit(1); } } static int Read(void *buf, int nb) { int n; n = read(0,buf,nb); if (n < 0) { fprintf(stderr,"%s: input read error: %s\n",__progname,strerror(errno)); exit(1); } return(n); } { if (ac < 2) usage(); if (!strcmp(av[1],"-iv")) { int i; if (ac != 2) usage(); setup_iv(&nulchar); for (i=0;i<8;i++) printf("%02lx",0xff&(unsigned long int)iv[i]); printf("\n"); } else if (!strcmp(av[1],"-e") || !strcmp(av[1],"-eb") || !strcmp(av[1],"-ev") || !strcmp(av[1],"-ebv") ) { int nb; unsigned char *bp; int n; int i; unsigned long int v; setup_key(av[2]); idea_setkey_e(&keyhash[0],&k); if (!strcmp(av[1],"-e")) { if (ac != 3) usage(); setup_iv(&nulchar); } else { if (ac != 4) usage(); if (strlen(av[3]) != 16) usage(); for (i=0;i<8;i++) { if (sscanf(av[3]+(i*2),"%2lx",&v) != 1) usage(); iv[i] = v; } } idea_crypt(&iv[0],&k,&fb[0]); Write(&fb[0],8); while (1) { nb = Read(&buf[SLOP],MAXBLK); if (nb == 0) break; bp = &buf[SLOP]; n = nb; *--bp = n & 0x7f; nb ++; for (n>>=7;n>0;n>>=7,nb++) *--bp = 0x80 | (n & 0x7f); nb = (nb + 7) >> 3; for (n=nb;n>0;n--) { for (i=7;i>=0;i--) fb[i] ^= bp[i]; idea_crypt(&fb[0],&k,&fb[0]); bcopy(fb,bp,8); bp += 8; } Write(bp-(8*nb),8*nb); } } else if (!strcmp(av[1],"-d")) { unsigned int nb; unsigned int nbc; unsigned int n; unsigned int npad; int nr; int nn; unsigned int nw; unsigned char *bp; unsigned char *cp; int i; int j; if (ac != 3) usage(); setup_key(av[2]); idea_setkey_d(&keyhash[0],&k); nb = 8; while (nb > 0) { n = Read(&fb[8-nb],nb); if (n == 0) { fprintf(stderr,"%s: input too short\n",__progname); exit(1); } nb -= n; } nbc = 0; nb = 0; bp = &buf[0]; nn = 0; n = 0; while (1) { if (nbc < 1) { if (nb > 0) bcopy(bp,&buf[0],nb); bp = &buf[0]; nr = Read(&buf[nb],MAXBLK); if (nr == 0) break; nb += nr; cp = &buf[0]; for (i=nb/8;i>0;i--) { bcopy(cp,&ctmp[0],8); idea_crypt(&ctmp[0],&k,cp); for (j=7;j>=0;j--) cp[j] ^= fb[j]; bcopy(&ctmp[0],&fb[0],8); cp += 8; } nbc = nb & ~7; nb &= 7; continue; } if (nn >= 0) { n = (n << 7) | (*bp++ & 0x7f); nn ++; nbc --; if (! (bp[-1] & 0x80)) { npad = 7 & (8 - ((n+nn) & 7)); nn = -1; } } else { if (n > 0) { nw = (n <= nbc) ? n : nbc; Write(bp,nw); bp += nw; nbc -= nw; n -= nw; } if ((n == 0) && (npad > 0)) { nw = (npad <= nbc) ? npad : nbc; bp += nw; nbc -= nw; npad = 0; } if ((n == 0) && (npad == 0)) { nn = 0; } } } if (nn > 0) { fprintf(stderr,"%s: warning: EOF while reading block size\n",__progname); } else if (n > 0) { fprintf(stderr,"%s: warning: EOF partway through a block\n",__progname); } } else if (!strcmp(av[1],"-ke")) { int i; if (ac != 3) usage(); setup_key(av[2]); idea_setkey_e(&keyhash[0],&k); for (i=0;i<16;i++) printf("%02x",0xff&(unsigned int)keyhash[i]); printf(" "); for (i=0;i<52;i++) printf("%04lx",(unsigned long int)k.Z[i]); printf("\n"); } else if (!strcmp(av[1],"-kd")) { int i; if (ac != 3) usage(); setup_key(av[2]); idea_setkey_d(&keyhash[0],&k); for (i=0;i<16;i++) printf("%02x",0xff&(unsigned int)keyhash[i]); printf(" "); for (i=0;i<52;i++) printf("%04lx",(unsigned long int)k.Z[i]); printf("\n"); } else if ( !strcmp(av[1],"-t") || !strcmp(av[1],"-te") || !strcmp(av[1],"-td") ) { int i; unsigned long int v; if (ac != 4) usage(); switch (av[1][2]) { case '\0': if (strlen(av[2]) != 208) usage(); for (i=0;i<52;i++) { if (sscanf(av[2]+(i*4),"%4lx",&v) != 1) usage(); k.Z[i] = v; } break; case 'e': if (strlen(av[2]) != 32) usage(); for (i=0;i<16;i++) { if (sscanf(av[2]+(i*2),"%2lx",&v) != 1) usage(); keyhash[i] = v; } idea_setkey_e(&keyhash[0],&k); break; case 'd': if (strlen(av[2]) != 32) usage(); for (i=0;i<16;i++) { if (sscanf(av[2]+(i*2),"%2lx",&v) != 1) usage(); keyhash[i] = v; } idea_setkey_d(&keyhash[0],&k); break; } if (strlen(av[3]) != 16) usage(); for (i=0;i<8;i++) { if (sscanf(av[3]+(i*2),"%2lx",&v) != 1) usage(); ctmp[i] = v; } idea_crypt(&ctmp[0],&k,&ctmp[0]); for (i=0;i<8;i++) printf("%02lx",0xff&(unsigned long int)ctmp[i]); printf("\n"); } else { usage(); } exit(0); } #endif