Check-in [5468ec7c5e]
Not logged in
Overview

SHA1 Hash:5468ec7c5ed45e567e0cee6780a7c37daa274356
Date: 2009-03-26 15:32:43
User: drh
Edited Comment:Incremental changes toward encrypting sync traffic. The changes are incomplete, but all legacy functionality appears to still works.
Original Comment:Incremental changes toward encrypting sync traffic. The changes are incomplete, but all legacy functionality appears to still works.
Timelines: ancestors | descendants | both | experimental
Other Links: files | ZIP archive | manifest

Tags And Properties
Changes
[hide diffs]

Modified src/blob.c from [1998856256] to [4adbb9d2f8].

@@ -843,10 +843,122 @@
     blob_reset(&b1);
     blob_reset(&b2);
     blob_reset(&b3);
   }
   printf("ok\n");
+}
+
+/*
+** Do an RC4 encryption/decryption.
+**
+** The key is formed by concatenating zPassword and aNonce and taking
+** the sha1 hash of the result.  The first 1000 bytes of the rc4 bytestream
+** are discarded.  The next nIn bytes of the rc4 bytestream are XORed
+** against aIn and the result is written into aOut.
+*/
+static void rc4_coder(
+  const char *zPassword,   /* The password */
+  const char *aNonce,      /* One-time nonce for this encryption */
+  int nNonce,              /* Number of bytes in the nonce */
+  const char *aIn,         /* Input text */
+  int nIn,                 /* Number of bytes of input text */
+  char *aOut               /* Output text */
+){
+  Blob key;
+  int k;
+  unsigned char i, j, t;
+  unsigned char s[256];
+  unsigned char *pKey;
+  int nKey;
+
+  blob_zero(&key);
+  blob_append(&key, zPassword, -1);
+  blob_append(&key, aNonce, nNonce);
+  sha1sum_blob(&key, &key);
+  pKey = (unsigned char*)key.aData;
+  nKey = key.nUsed;
+
+  /* Key the RC4 codec */
+  for(k=0; k<256; k++) s[k] = k;
+  for(i=j=0, k=0; k<256; k++, i++){
+    j += pKey[i % nKey] + s[i];
+    t = s[i];
+    s[i] = s[j];
+    s[j] = t;
+  }
+  blob_reset(&key);
+
+  /* Skip the first 1000 bytes of output */
+  i = j = 0;
+  for(k=0; k<1000; k++){
+    i++;
+    j += s[i];
+    t = s[i];
+    s[i] = s[j];
+    s[j] = t;
+  }
+
+  /* Encode nIn bytes */
+  for(k=0; k<nIn; k++){
+    i++;
+    j += s[i];
+    t = s[i];
+    s[i] = s[j];
+    s[j] = t;
+    aOut[k] = aIn[k] ^ s[(s[i] + s[j])&255];
+  }
+}
+
+/*
+** Encrypt a blob using RC4.
+**
+** The key is constructed by taking the sha1 hash of the password
+** and a random 20-byte nonce.  This nonce becomes the first 20 bytes
+** of the encrypted output.  The first 1000 bytes of the RC4 byte stream
+** are discarded.  The input is XORed against the remaining RC4 byte stream
+** to generate the rest of the output.
+**
+** Only that portion of pIn beginning at the current cursor location and
+** extending to the end of the blob is encrypted.  Any content of pIn
+** prior to the current cursor position is ignored.
+**
+** Because of the prepended nonce, the output will be 20 bytes larger
+** than the input.
+**
+** pOut should be initialized prior to invoking this routine.  pOut might
+** already contain other content.  The encryption is appended to pOut.
+*/
+void blob_encrypt(Blob *pIn, const char *zPassword, Blob *pOut){
+  unsigned char aNonce[20];
+  unsigned char *aIn;
+  int nIn;
+  unsigned char *aOut;
+
+  sqlite3_randomness(sizeof(aNonce), aNonce);
+  aIn = (unsigned char*)pIn->aData;
+  aIn += pIn->iCursor;
+  nIn = pIn->nUsed - pIn->iCursor;
+  if( nIn<=0 ) return;
+
+}
+
+/*
+** Decrypt a blob.
+**
+** This routine undoes the work of blob_encrypt.  pIn should be a blob
+** that was generated by blob_encrypt.  Assuming the same password is
+** used, the original unencrypted text will be written into pOut.
+**
+** Only that portion of pIn beginning at the current cursor location and
+** extending to the end of the blob is decrypted.  Any content of pIn
+** prior to the current cursor position is ignored.
+**
+** pOut should be initialized prior to invoking this routine.  pOut might
+** already contain other content.  The encryption is appended to pOut.
+*/
+void blob_decrypt(Blob *pIn, const char *zPassword, Blob *pOut){
+  /* TBD... */
 }
 
 #ifdef __MINGW32__
 /*
 ** Convert every \n character in the given blob into \r\n.

Modified src/http.c from [099ac83ebe] to [a7c94bef96].

@@ -279,25 +279,39 @@
   http_close();
   return 0;
 }
 
 /*
-** Sign the content in pSend, compress it, and send it to the server
-** via HTTP.  Get a reply, uncompress the reply, and store the reply
-** in pRecv.  pRecv is assumed to be uninitialized when
+** Sign the content in pSend, compress it (if compression is turned on),
+** encrypt it (if security is turned on), and send it to the server
+** via HTTP.  Get a reply, decrypt and uncompress the reply, and store
+** the reply in pRecv.  pRecv is assumed to be uninitialized when
 ** this routine is called - this routine will initialize it.
 **
 ** The server address is contain in the "g" global structure.  The
 ** url_parse() routine should have been called prior to this routine
 ** in order to fill this structure appropriately.
 */
 void http_exchange(Blob *pSend, Blob *pRecv){
-  Blob login, nonce, sig, pw, payload, hdr;
+  Blob login;      /* The "login" card at the beginning of the payload */
+  Blob nonce;      /* The password verificatin nonce on the login card */
+  Blob sig;        /* The signature on the login card */
+  Blob pw;         /* The user password prefixed by the nonce */
+  Blob payload;    /* The HTTP request payload */
+  Blob hdr;        /* The HTTP request header */
   const char *zSep;
   int i;
   int cnt = 0;
 
+  /* Compute the login card.  This card is of the form:
+  **
+  **      login USERID NONCE SIGNATURE
+  **
+  ** The NONCE is a unique string - never to be reused.  In this case,
+  ** the nonce is the SHA1 hash of the rest of the payload.  The SIGNATURE
+  ** is the SHA1 hash of the NONCE and the user password concatenated.
+  */
   blob_zero(&nonce);
   blob_zero(&pw);
   sha1sum_blob(pSend, &nonce);
   blob_copy(&pw, &nonce);
   blob_zero(&login);
@@ -324,17 +338,23 @@
     blob_appendf(&login, "login %s %b %b\n", g.urlUser, &nonce, &sig);
   }
   blob_reset(&nonce);
   blob_reset(&pw);
   blob_reset(&sig);
+
+  /* Construct the payload, which includes the login card.
+  */
   if( g.fHttpTrace ){
     payload = login;
     blob_append(&payload, blob_buffer(pSend), blob_size(pSend));
   }else{
     blob_compress2(&login, pSend, &payload);
     blob_reset(&login);
   }
+
+  /* Construct the HTTP request header
+  */
   blob_zero(&hdr);
   i = strlen(g.urlPath);
   if( i>0 && g.urlPath[i-1]=='/' ){
     zSep = "";
   }else{
@@ -369,18 +389,26 @@
       fwrite(blob_buffer(&hdr), 1, blob_size(&hdr), out);
       fwrite(blob_buffer(&payload), 1, blob_size(&payload), out);
       fclose(out);
     }
   }
+
+  /* Send the header and payload to the server.  Get the reply.  If
+  ** the first attempt is unsuccessful, do a second attempt.
+  */
   for(cnt=0; cnt<2; cnt++){
     if( http_send_recv(&hdr, &payload, pRecv) ) break;
   }
   if( cnt>=2 ){
     fossil_fatal("connection to server failed");
   }
   blob_reset(&hdr);
   blob_reset(&payload);
+
+  /* Process the reply.  pRecv contains only the payload of the
+  ** reply message, not the header.
+  */
   if( g.fHttpTrace ){
     printf("HTTP RECEIVE:\n%s\n=======================\n", blob_str(pRecv));
   }else{
     blob_uncompress(pRecv, pRecv);
   }