anchor.diff:          let url = (clusterURL username) + "1.1/" + username + "/storage/crypto/keys"
           fetchUrlResponse url "GET" (Some (username, password)) None None None
   
  -
  -    // decrypt payload
  -    // https://docs.services.mozilla.com/sync/storageformat5.html
       type CryptoKeysPayload = { iv         : string
                                  ciphertext : string
                                  hmac       : string }
  -
   
       let writeSecretKeysToDisk username password (file : string option) = 
           let secretKeys = fetchCryptoKeys username password
  
positive.code:             [||]
  
  
  
  
      type SyncKeyBundle = { encryption_key : byte[]; hmac_local : byte[] }
  
      let syncKeyBundle username key =
          let info = "Sync-AES_256_CBC-HMAC256" + username
          let hmac256 = new HMACSHA256(key)
          let T1 = hmac256.ComputeHash (Array.append (info |> stringToBytes ) [| 1uy |] )
          let T2 = hmac256.ComputeHash (Array.append T1 <| Array.append (info |> stringToBytes) [| 2uy |])   
          { encryption_key = T1 ; hmac_local = T2 }
      
  
      // http://social.msdn.microsoft.com/Forums/en-US/aa51d82c-3868-4da8-b697-9a26926d0806/c-and-php-encryption-and-decryption-rijndaelaes-256?forum=csharplanguage
      let DecryptIt (s : string) (key : byte[]) (iv : byte[]) =
          let rijn = new RijndaelManaged()
          rijn.Mode <- CipherMode.ECB
          rijn.Padding <- PaddingMode.Zeros
          use msDecrypt = new MemoryStream(Convert.FromBase64String(s))
          use decryptor = rijn.CreateDecryptor(key, iv)
          use csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)
          use swDecrypt = new StreamReader(csDecrypt)
          let result = swDecrypt.ReadToEnd()
          rijn.Clear()
          result
  
      // http://msdn.microsoft.com/en-us/library/system.security.cryptography.aescryptoserviceprovider%28v=vs.110%29.aspx
      let DecryptAES (s : string) (key : byte[]) (iv : byte[]) =
          // Check arguments.
          if s.Length * key.Length * iv.Length = 0 then ""
          else
              // Create an AesCryptoServiceProvider object 
              // with the specified key and IV. 
  
negative.code:     with | _ -> failwith "writeSecretKeysToDisk failed"
  
      let sk = readSecretKeysFromDisk None |> JsonValue.Parse
      let sk_pl = (sk?payload).AsString() |> JsonValue.Parse
  
  // https://docs.services.mozilla.com/sync/storageformat5.html
  //
  //    ciphertext  = record.ciphertext
  //    iv          = record.iv
  //    record_hmac = record.hmac
  //
  //    encryption_key = bundle.encryption_key
  //    hmac_key       = bundle.hmac_key
  //
  //    local_hmac = HMACSHA256(hmac_key, base64(ciphertext))
  //
  //    if local_hmac != record_hmac:
  //      throw Error("HMAC verification failed.")
  //
  //    cleartext = AESDecrypt(ciphertext, encryption_key, iv)
  
      let record = { iv         = (sk_pl?IV).AsString()
                     ciphertext = (sk_pl?ciphertext).AsString()
                     hmac       = (sk_pl?hmac).AsString() }
  
      let bundle = syncKeyBundle secrets.username (secrets.encryptionpassphrase |> base32Decode)
  
      let local_hmac = record.ciphertext |> Convert.FromBase64String |> (new HMACSHA256(bundle.hmac_key)).ComputeHash
  
      let cleartext = DecryptAES record.ciphertext bundle.encryption_key (record.iv |> Convert.FromBase64String)
  