Wize /
Xor Salt
Search:  

Xor-Salt Encryption

NOTE: Encryption changed after Wize 2.1.

Xor-Salt implements low-rent, symmetrical encryption by xor-ing data with a password and salt. The salt is generated from the password itself, and gets reshuffled at periods of irregular length throughout the encryption.

DISCLAIMER: Xor-Salt does NOT provide commercial grade encryption!!! In fact, Xor-Salt uses no cryptographic math what-so-ever. For that you should use SSL.

Nevertheless, for many real world applications SSL is overkill. Xor-Salt offers simple encryption in a very small code base. And, using Xor-Salt to encrypt with the 128 bit MD5 of a password provides pretty good secrecy.

An example application using Xor-Salt is Sqlite Over Sockets.

In place of a detailed description, code is provided below:


/* BSD copyright 2008 - Peter MacDonald - http://pdqi.com
 * Xor-salt encryption.  Returns encrypted string of length len
 * where in-len == out-len and odata and data may be the same.
 * If odata is NULL, it gets alloc'ed.
 * The value of saltsz is >=0 && <=256. Typical values: 4 or 8.
 */
static char *
saltxorstr(
    int plen,
    char *password,
    int len,
    char *data,
    char *odata,
    int saltsz
) {
    unsigned char *ip, *pp, *ib, *c, rval, seed, salts[256], ppBuf[BUFSIZ+20];
    int i=0, j, p, n, random = 0;

    ip = password;
    ib = data;
    if (plen<1) {
	return NULL;
    }
    if (saltsz<0 || saltsz>256) {
	return NULL;
    }
    if (odata != NULL) {
        c = (unsigned char *)odata;
    } else {
        c = (unsigned char *)ckalloc(len*sizeof(unsigned char));
    }
    if (plen<BUFSIZ) {
	pp = ppBuf;
    } else {
        pp = (unsigned char *)ckalloc((plen+20)*sizeof(unsigned char));
    }
    strcpy(pp, ip);
    for (i=0; i<16; i++) {
	pp[plen+i] = ip[i%plen];
    }
    p = -1;
    if (saltsz) {
        for (i=0; i<saltsz; i++) {
	    salts[i] = 0;
        }
        /* Rotate password bits 90 degrees and skew. */
        for (i=0; i<plen; i+=8) {
	    for (j=0; j<8; j++) {
	       unsigned char nv;
	       nv = (pp[i+j]&0x1)|(pp[i+j+4]&0x10)| \
		    (pp[i+j+1]&0x2)|(pp[i+j+5]&0x20)| \
		    (pp[i+j+2]&0x4)|(pp[i+j+6]&0x40)| \
		    (pp[i+j+3]&0x8)|(pp[i+j+7]&0x80);
	       salts[j%saltsz] ^= nv;
	    }
	}
	/* Use full password to generate the seed starting value. */
        seed = ip[0];
	for (i=1; i<plen; i++) {
	    seed=seed^ip[i];
	}
	p = ((seed%plen)-1);
    }
    n = -1;
    for (i=0; i<len; i++) {
	n = ((n+1)%saltsz);
	p++;
	if (p>=plen) p=0;
	rval=ip[p];
	if (saltsz) {
	    /* At irregular intervals shuffle the salts and seed. */
	    if (((p+random)%plen) == (seed%plen)) {
		random = seed;
		seed ^= salts[p%saltsz];
	        for (j=0; j<saltsz; j++) {
                    salts[j] = ((salts[j]<<1) | ((salts[j]&0x80) != 0));
		}
	    }
	    rval = ((ip[p]^salts[n])^seed);
	}
	c[i] = (ib[i]^rval);
    }
    if (pp != ppBuf) {
        ckfree(pp);
    }
    return (char *)c;
}

/*
 * Xor based symmetric encryption.
 * If called with -nosalt or -saltsize 0, fall back to plain old xor.
 */
static int
xorstrcmd(ClientData clientData, Tcl_Interp *interp,
	int objc, Tcl_Obj *CONST objv[]) {
    Tcl_Obj *result;
    char *ib;
    char *ip;
    int plen, olen, saltsz=8;
    unsigned char *c, cBuf[BUFSIZ+10];

    while (1) {
        if ( objc>=4 && strcmp("-nosalt", Tcl_GetString(objv[1])) == 0) {
	    saltsz=0;
	    objc--;
	    objv++;
	    continue;
        }
        if ( objc>=5 && strcmp("-saltsize", Tcl_GetString(objv[1])) == 0) {
	    if (Tcl_GetIntFromObj(interp, objv[2], &saltsz) != TCL_OK) {
	        return TCL_ERROR;
	    }
	    if (saltsz<0 || saltsz>256) {
	        Tcl_SetObjResult(interp, Tcl_NewStringObj("salt <0 or >256 ", -1));
	        return TCL_ERROR;
	    }
	    objc-=2;
	    objv+=2;
	    continue;
        }
	break;
    }
    if (objc != 3) {
	Tcl_SetObjResult(interp, Tcl_NewStringObj(
	    "usage: xorcrypt ?-nosalt? ?-saltsize N? password data", -1));
	return TCL_ERROR;
    }
    ip = Tcl_GetStringFromObj(objv[1], &plen);
    ib = Tcl_GetByteArrayFromObj(objv[2], &olen);
    if (plen<1) {
	Tcl_SetObjResult(interp, Tcl_NewStringObj("null password", -1));
	return TCL_ERROR;
    }
    c = saltxorstr(plen, ip, olen, ib, (olen<BUFSIZ?cBuf:NULL), saltsz);
    if (c == NULL) {
	Tcl_SetObjResult(interp, Tcl_NewStringObj("crypt failure", -1));
	return TCL_ERROR;
    }
    result=Tcl_NewByteArrayObj(c, olen);
    if (c != cBuf) {
       ckfree(c);
    }
    Tcl_SetObjResult(interp, result);
    return TCL_OK;
}

© 2008 Peter MacDonald

Page last modified on June 06, 2009, at 03:56 PM