PC1.cc

Go to the documentation of this file.
00001 // $Id: PC1.cc 30949 2009-11-02 16:37:58Z ganis $
00002 
00003 const char *PC1CVSID = "$Id: PC1.cc 30949 2009-11-02 16:37:58Z ganis $";
00004 /* ----------------------------------------------------------------------- *
00005  *                                                                         *
00006  * PC1.cc                                                                  *
00007  *                                                                         *
00008  * C++ adaptation of PC1 implementation written by Alexander PUKALL 1991.  *
00009  *                                                                         *
00010  * Reference:  http://membres.lycos.fr/pc1/                                *
00011  *                                                                         *
00012  * Description:                                                            *
00013  * PC1 Cipher Algorithm (Pukall Cipher 1) for encryption/decryption.       *
00014  * One-way hash for password encryption also provided.                     *
00015  *                                                                         *
00016  * Key length is 256 bits                                                  *
00017  *                                                                         *
00018  * Free code no restriction to use please include the name of the Author   *
00019  * in the final software                                                   *
00020  * Tested with Turbo C 2.0 for DOS and Microsoft Visual C++ 5.0 for Win 32 *
00021  *                                                                         *
00022  * Adapted by G. Ganis (g.ganis@cern.ch), January 2005                     *
00023  * ----------------------------------------------------------------------- */
00024 #include <stdio.h>
00025 #include <stdlib.h>
00026 #include <unistd.h>
00027 #include <string.h>
00028 #include "PC1.hh"
00029 
00030 typedef unsigned short ushort;
00031 
00032 // The following string is not a password nor a key, only a random data input
00033 // used if the user password or key is too short
00034 static unsigned char cleref[kPC1LENGTH] =
00035    {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p',
00036     'q','r','s','t','u','v','w','x','y','z','0','1','2','3','4','5'};
00037 
00038 namespace PC1 {
00039 
00040 /* ------------------------------------------------------------------- *
00041  *         Local static auxilliary functions                           *
00042  * ------------------------------------------------------------------- */
00043 //____________________________________________________________________
00044 static ushort code(ushort &ind, ushort &si, ushort &x1a2, ushort *x1a0)
00045 {
00046    // Encoding
00047    ushort ax, bx, cx, dx;
00048    ushort tmp;
00049 
00050    dx = x1a2 + ind;
00051    ax = x1a0[ind];
00052    cx = 0x015a;
00053    bx = 0x4e35;
00054 
00055    tmp = ax;
00056    ax  = si;
00057    si  = tmp;
00058 
00059    tmp = ax;
00060    ax  = dx;
00061    dx  = tmp;
00062 
00063    if (ax != 0) {
00064       ax=ax*bx;
00065    }
00066 
00067    tmp = ax;
00068    ax  = cx;
00069    cx  = tmp;
00070 
00071    if (ax != 0) {
00072       ax = ax*si;
00073       cx = ax+cx;
00074    }
00075 
00076    tmp = ax;
00077    ax  = si;
00078    si  = tmp;
00079    ax  = ax*bx;
00080    dx  = cx+dx;
00081 
00082    ax += 1;
00083 
00084    x1a2 = dx;
00085    x1a0[ind] = ax;
00086 
00087    ushort res = ax^dx;
00088    ind += 1;
00089    return res;
00090 }
00091 
00092 //____________________________________________________________________
00093 static void assemble(unsigned char *cle, ushort &inter,
00094                      ushort &si, ushort &x1a2)
00095 {
00096    // Assembling
00097    ushort ind = 0;
00098    ushort x1a0[kPC1LENGTH/2];
00099 
00100    x1a0[0] = cle[0]*256 + cle[1];
00101    ushort res = code(ind,si,x1a2,x1a0);
00102    inter = res;
00103 
00104    int j;
00105    for (j = 0; j < 15; j++) {
00106       x1a0[j+1] = x1a0[j]^(cle[2*(j+1)]*256 + cle[2*(j+1)+1]);
00107       res = code(ind,si,x1a2,x1a0);
00108       inter = inter^res;
00109    }
00110 }
00111 
00112 } // namespace PC1
00113 
00114 /* ------------------------------------------------------------------- *
00115  *                          Public functions                           *
00116  * ------------------------------------------------------------------- */
00117 
00118 //______________________________________________________________________
00119 int PC1HashFun(const char *in, int lin, const char *sa, int lsa,
00120                                                         int it, char *out)
00121 {
00122    // One-way hash function.
00123    // Calculate hash of lin bytes at in (max kPC1LENGTH), using salt
00124    // sa (max length kPC1LENGTH bytes).
00125    // Number of iterations to finalize is 'it'.
00126    // If the salt is not given, the buffer in is used as salt.
00127    // The output buffer must be allocated by the caller to contain at
00128    // least 2*kPC1LENGTH+1 bytes.
00129    // Return length of hash in bytes or -1 in case of wrong / incomplete
00130    // input arguments
00131 
00132    // Check inputs
00133    if (!in || lin <= 0 || !out)
00134       return -1;
00135 
00136    //
00137    // Declarations and initializations
00138    unsigned char bin[kPC1LENGTH];
00139    unsigned char cle[kPC1LENGTH];
00140    unsigned char tab[kPC1LENGTH] = {0};
00141    unsigned int ix = 0;
00142    int j = 0;
00143    memset((void *)&bin[0],0,kPC1LENGTH);
00144    memset((void *)&tab[0],0,kPC1LENGTH);
00145 
00146    //
00147    // Fill bin with the first lin bytes of in
00148    int lbin = (lin > kPC1LENGTH) ? kPC1LENGTH : lin;
00149    memcpy(&bin[0],in,lbin);
00150 
00151    //
00152    // Fill cle ...
00153    int lcle = 0;
00154    if (sa && lsa > 0) {
00155       // ... with the salt
00156       for( j = 0; j < lsa; j++) {
00157          cle[j] = sa[j];
00158       }
00159       lcle = lsa;
00160    } else {
00161       // salt not given: use the password itself
00162       for( j = 0; j < lin; j++) {
00163          cle[j] = in[j];
00164       }
00165       lcle = lin;
00166    }
00167    //
00168    // If too short, complete cle with the ref string 
00169    for( j = lcle; j < kPC1LENGTH; j++) {
00170       cle[j] = cleref[j];
00171    }
00172 
00173    //
00174    // First round
00175    ushort si = 0;
00176    ushort inter = 0;
00177    ushort x1a2= 0;
00178    for (j = 0; j < kPC1LENGTH; j++) {
00179       short c = bin[j];
00180       PC1::assemble(cle,inter,si,x1a2);
00181       ushort cfc = inter >> 8;
00182       ushort cfd = inter & 0xFF; // cfc^cfd = random byte
00183       int k = 0;
00184       for( ; k < kPC1LENGTH; k++) {
00185          cle[k] = cle[k]^c;
00186       }
00187       c = c^(cfc^cfd);
00188       tab[ix] = tab[ix]^c;
00189       ix += 1;
00190       if (ix >= kPC1LENGTH) ix = 0;
00191    }
00192 
00193    //
00194    // Second round
00195    // to avoid dictionary attack on the passwords
00196    // int it = 63254;
00197    for (j = 1; j <= it; j++) {
00198       short c = tab[ix];
00199       PC1::assemble(cle,inter,si,x1a2);
00200       ushort cfc = inter >> 8;
00201       ushort cfd = inter & 0xFF; // cfc^cfd = random byte
00202       int k = 0;
00203       for (; k < kPC1LENGTH; k++) {
00204          cle[k] = cle[k]^c;
00205       }
00206       c = c^(cfc^cfd);
00207       tab[ix] = tab[ix]^c;
00208       ix += 1;
00209       if (ix >= kPC1LENGTH) ix = 0;
00210    }
00211 
00212    //
00213    // Prepare output 
00214    int k = 0;
00215    for( j = 0; j < kPC1LENGTH; j++) {
00216       // we split the 'c' crypted byte into two 4 bits
00217       // parts 'd' and 'e'
00218       short d = (tab[j] >> 4);
00219       short e = (tab[j] & 15);
00220       // write the two 4 bits parts in the output buffer
00221       // as text range from A to P
00222       out[k++] = d + 0x61;
00223       out[k++] = e + 0x61;
00224    }
00225    // Null terminated
00226    out[k] = 0;
00227 
00228    // Return buffer length
00229    return k;
00230 }
00231 
00232 //______________________________________________________________________
00233 int PC1Encrypt(const char *in, int lin, const char *key, int lkey, char *out)
00234 {
00235    // Encrypting routine.
00236    // Encode lin bytes at in using key (max key length kPC1LENGTH).
00237    // The output buffer must be allocated by the caller to contain at
00238    // least 2*lin bytes.
00239    // Return length of encrypted string in bytes or -1 in case of
00240    // wrong / incomplete input arguments
00241 
00242    // Check inputs
00243    if (!in || lin <= 0 || !key || lkey <= 0 || !out)
00244       return -1;
00245 
00246    //
00247    // Declarations and initializations
00248    unsigned char cle[kPC1LENGTH];
00249    int j = 0;
00250 
00251    //
00252    // Fill cle with the given key
00253    int lk = (lkey > kPC1LENGTH) ? kPC1LENGTH : lkey;
00254    for( j = 0; j < lk; j++) {
00255       cle[j] = key[j];
00256    }
00257    //
00258    // If too short, complete with the ref string 
00259    for( j = lk; j < kPC1LENGTH; j++) {
00260       cle[j] = cleref[j];
00261    }
00262 
00263    //
00264    // Define internal variables
00265    ushort si = 0;
00266    ushort inter = 0;
00267    ushort x1a2= 0;
00268    //
00269    // Encrypt
00270    int n = 0;
00271    for (j = 0; j < lin; j++) {
00272 
00273       short c = in[j];
00274       PC1::assemble(cle,inter,si,x1a2);
00275       ushort cfc = inter >> 8;
00276       ushort cfd = inter & 0xFF; // cfc^cfd = random byte
00277       int k = 0;
00278       for( ; k < kPC1LENGTH; k++) {
00279          cle[k] = cle[k]^c;
00280       }
00281       c = c^(cfc^cfd);
00282 
00283       // we split the 'c' crypted byte into two 4 bits
00284       // parts 'd' and 'e'
00285       short d = (c >> 4);
00286       short e = (c & 15);
00287 
00288       // write the two 4 bits parts in the output buffer
00289       // as text range from A to P
00290       out[n++] = d + 0x61;
00291       out[n++] = e + 0x61;
00292    }
00293 
00294    // Return buffer length
00295    return n;
00296 }
00297 
00298 //______________________________________________________________________
00299 int PC1Decrypt(const char *in, int lin, const char *key, int lkey, char *out)
00300 {
00301    // Decrypting routine.
00302    // Decrypt lin bytes at in using key (max key length kPC1LENGTH).
00303    // The output buffer must be allocated by the caller to contain at
00304    // least lin/2 bytes.
00305    // Return length of decrypted string in bytes or -1 in case of
00306    // wrong / incomplete input arguments
00307 
00308    // Check inputs
00309    if (!in || lin <= 0 || !key || lkey <= 0 || !out)
00310       return -1;
00311 
00312    //
00313    // Declarations and initializations
00314    unsigned char cle[kPC1LENGTH];
00315    int j = 0;
00316 
00317    //
00318    // Fill cle with the given key
00319    int lk = (lkey > kPC1LENGTH) ? kPC1LENGTH : lkey;
00320    for( j = 0; j < lk; j++) {
00321       cle[j] = key[j];
00322    }
00323    //
00324    // If too short, complete with the ref string 
00325    for( j = lk; j < kPC1LENGTH; j++) {
00326       cle[j] = cleref[j];
00327    }
00328 
00329    //
00330    // Define internal variables
00331    ushort si = 0;
00332    ushort inter = 0;
00333    ushort x1a2= 0;
00334    //
00335    // Decrypt
00336    int n = 0;
00337    for (j = 0; j < lin; j += 2 ) {
00338 
00339       short d = in[j]   - 0x61;
00340       short e = in[j+1] - 0x61;
00341       d = d << 4;
00342       short c = d + e;
00343 
00344       PC1::assemble(cle,inter,si,x1a2);
00345       ushort cfc = inter >> 8;
00346       ushort cfd = inter & 0xFF; // cfc^cfd = random byte
00347 
00348       c = c^(cfc^cfd);
00349       int k = 0;
00350       for( ; k < kPC1LENGTH; k++) {
00351          cle[k] = cle[k]^c;
00352       }
00353       out[n++] = c;
00354    }
00355 
00356    // Return buffer length
00357    return n;
00358 }

Generated on Tue Jul 5 14:46:32 2011 for ROOT_528-00b_version by  doxygen 1.5.1