// Generated by IcedCoffeeScript 1.7.1-f
(function() {
  var AES, Base, CURRENT_VERSION, Concat, Encryptor, HMAC_SHA256, PBKDF2, SHA512, Scrypt, TwoFish, V, WordArray, XOR, ctr, encrypt, iced, make_esc, prng, salsa20, util, __iced_k, __iced_k_noop, _ref,
    __hasProp = {}.hasOwnProperty,
    __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };

  iced = require('iced-runtime');
  __iced_k = __iced_k_noop = function() {};

  WordArray = require('./wordarray').WordArray;

  salsa20 = require('./salsa20');

  AES = require('./aes').AES;

  TwoFish = require('./twofish').TwoFish;

  ctr = require('./ctr');

  _ref = require('./combine'), XOR = _ref.XOR, Concat = _ref.Concat;

  SHA512 = require('./sha512').SHA512;

  PBKDF2 = require('./pbkdf2').PBKDF2;

  Scrypt = require('./scrypt').Scrypt;

  util = require('./util');

  prng = require('./prng');

  make_esc = require('iced-error').make_esc;

  HMAC_SHA256 = require('./hmac').HMAC_SHA256;

  V = {
    "1": {
      header: [0x1c94d7de, 1],
      salt_size: 8,
      xsalsa20_rev: true,
      kdf: {
        klass: PBKDF2,
        opts: {
          c: 1024,
          klass: XOR
        }
      },
      hmac_key_size: 768 / 8
    },
    "2": {
      header: [0x1c94d7de, 2],
      salt_size: 16,
      xsalsa20_rev: true,
      kdf: {
        klass: Scrypt,
        opts: {
          c: 64,
          klass: XOR,
          N: 12,
          r: 8,
          p: 1
        }
      },
      hmac_key_size: 768 / 8
    },
    "3": {
      header: [0x1c94d7de, 3],
      salt_size: 16,
      xsalsa20_rev: false,
      kdf: {
        klass: Scrypt,
        opts: {
          c: 1,
          klass: HMAC_SHA256,
          N: 15,
          r: 8,
          p: 1
        }
      },
      hmac_key_size: 768 / 8
    }
  };

  exports.CURRENT_VERSION = CURRENT_VERSION = 3;

  Base = (function() {
    function Base(_arg) {
      var key, version;
      key = _arg.key, version = _arg.version;
      this.version = V[version != null ? version : CURRENT_VERSION];
      if (this.version == null) {
        throw new Error("unknown version: " + version);
      }
      this.set_key(key);
      this.derived_keys = {};
    }

    Base.prototype.kdf = function(_arg, cb) {
      var args, dkLen, end, extra_keymaterial, i, k, key, keys, len, lens, order, progress_hook, raw, salt, salt_hex, v, ___iced_passed_deferral, __iced_deferrals, __iced_k;
      __iced_k = __iced_k_noop;
      ___iced_passed_deferral = iced.findDeferral(arguments);
      salt = _arg.salt, extra_keymaterial = _arg.extra_keymaterial, progress_hook = _arg.progress_hook;
      (function(_this) {
        return (function(__iced_k) {
          __iced_deferrals = new iced.Deferrals(__iced_k, {
            parent: ___iced_passed_deferral,
            filename: "/home/max/src/keybase/triplesec/src/enc.iced",
            funcname: "Base.kdf"
          });
          _this._check_scrubbed(_this.key, "in KDF", cb, __iced_deferrals.defer({
            lineno: 94
          }));
          __iced_deferrals._fulfill();
        });
      })(this)((function(_this) {
        return function() {
          salt_hex = salt.to_hex();
          key = _this.key.clone();
          (function(__iced_k) {
            __iced_deferrals = new iced.Deferrals(__iced_k, {
              parent: ___iced_passed_deferral,
              filename: "/home/max/src/keybase/triplesec/src/enc.iced",
              funcname: "Base.kdf"
            });
            _this._check_scrubbed(key, "KDF", cb, __iced_deferrals.defer({
              lineno: 102
            }));
            __iced_deferrals._fulfill();
          })(function() {
            (function(__iced_k) {
              if ((keys = _this.derived_keys[salt_hex]) == null) {
                _this._kdf = new _this.version.kdf.klass(_this.version.kdf.opts);
                lens = {
                  hmac: _this.version.hmac_key_size,
                  aes: AES.keySize,
                  twofish: TwoFish.keySize,
                  salsa20: salsa20.Salsa20.keySize
                };
                order = ['hmac', 'aes', 'twofish', 'salsa20'];
                dkLen = extra_keymaterial || 0;
                for (k in lens) {
                  v = lens[k];
                  dkLen += v;
                }
                args = {
                  dkLen: dkLen,
                  key: key,
                  progress_hook: progress_hook,
                  salt: salt
                };
                (function(__iced_k) {
                  __iced_deferrals = new iced.Deferrals(__iced_k, {
                    parent: ___iced_passed_deferral,
                    filename: "/home/max/src/keybase/triplesec/src/enc.iced",
                    funcname: "Base.kdf"
                  });
                  _this._kdf.run(args, __iced_deferrals.defer({
                    assign_fn: (function() {
                      return function() {
                        return raw = arguments[0];
                      };
                    })(),
                    lineno: 121
                  }));
                  __iced_deferrals._fulfill();
                })(function() {
                  var _i, _len;
                  keys = {};
                  i = 0;
                  for (_i = 0, _len = order.length; _i < _len; _i++) {
                    k = order[_i];
                    v = lens[k];
                    len = v / 4;
                    end = i + len;
                    keys[k] = new WordArray(raw.words.slice(i, end));
                    i = end;
                  }
                  keys.extra = (new WordArray(raw.words.slice(end))).to_buffer();
                  return __iced_k(_this.derived_keys[salt_hex] = keys);
                });
              } else {
                return __iced_k();
              }
            })(function() {
              return cb(null, keys);
            });
          });
        };
      })(this));
    };

    Base.prototype.set_key = function(key) {
      var wakey;
      if (key != null) {
        wakey = WordArray.from_buffer(key);
        if (!this.key || !this.key.equal(wakey)) {
          this.scrub();
          return this.key = wakey;
        }
      } else {
        return this.scrub();
      }
    };

    Base.prototype._check_scrubbed = function(key, where, ecb, okcb) {
      if ((key != null) && !key.is_scrubbed()) {
        return okcb();
      } else {
        return ecb(new Error("" + where + ": Failed due to scrubbed key!"), null);
      }
    };

    Base.prototype.sign = function(_arg, cb) {
      var input, key, out, progress_hook, salt, ___iced_passed_deferral, __iced_deferrals, __iced_k;
      __iced_k = __iced_k_noop;
      ___iced_passed_deferral = iced.findDeferral(arguments);
      input = _arg.input, key = _arg.key, salt = _arg.salt, progress_hook = _arg.progress_hook;
      (function(_this) {
        return (function(__iced_k) {
          __iced_deferrals = new iced.Deferrals(__iced_k, {
            parent: ___iced_passed_deferral,
            filename: "/home/max/src/keybase/triplesec/src/enc.iced",
            funcname: "Base.sign"
          });
          _this._check_scrubbed(key, "HMAC", cb, __iced_deferrals.defer({
            lineno: 179
          }));
          __iced_deferrals._fulfill();
        });
      })(this)((function(_this) {
        return function() {
          input = (new WordArray(_this.version.header)).concat(salt).concat(input);
          (function(__iced_k) {
            __iced_deferrals = new iced.Deferrals(__iced_k, {
              parent: ___iced_passed_deferral,
              filename: "/home/max/src/keybase/triplesec/src/enc.iced",
              funcname: "Base.sign"
            });
            Concat.bulk_sign({
              key: key,
              input: input,
              progress_hook: progress_hook
            }, __iced_deferrals.defer({
              assign_fn: (function() {
                return function() {
                  return out = arguments[0];
                };
              })(),
              lineno: 181
            }));
            __iced_deferrals._fulfill();
          })(function() {
            input.scrub();
            return cb(null, out);
          });
        };
      })(this));
    };

    Base.prototype.run_salsa20 = function(_arg, cb) {
      var args, ct, input, iv, key, output_iv, progress_hook, ___iced_passed_deferral, __iced_deferrals, __iced_k;
      __iced_k = __iced_k_noop;
      ___iced_passed_deferral = iced.findDeferral(arguments);
      input = _arg.input, key = _arg.key, iv = _arg.iv, output_iv = _arg.output_iv, progress_hook = _arg.progress_hook;
      (function(_this) {
        return (function(__iced_k) {
          __iced_deferrals = new iced.Deferrals(__iced_k, {
            parent: ___iced_passed_deferral,
            filename: "/home/max/src/keybase/triplesec/src/enc.iced",
            funcname: "Base.run_salsa20"
          });
          _this._check_scrubbed(key, "Salsa20", cb, __iced_deferrals.defer({
            lineno: 197
          }));
          __iced_deferrals._fulfill();
        });
      })(this)((function(_this) {
        return function() {
          args = {
            input: input,
            progress_hook: progress_hook,
            key: key,
            iv: iv
          };
          if (_this.version.xsalsa20_rev) {
            args.key = key.clone().endian_reverse();
            args.iv = iv.clone().endian_reverse();
          }
          (function(__iced_k) {
            __iced_deferrals = new iced.Deferrals(__iced_k, {
              parent: ___iced_passed_deferral,
              filename: "/home/max/src/keybase/triplesec/src/enc.iced",
              funcname: "Base.run_salsa20"
            });
            salsa20.bulk_encrypt(args, __iced_deferrals.defer({
              assign_fn: (function() {
                return function() {
                  return ct = arguments[0];
                };
              })(),
              lineno: 209
            }));
            __iced_deferrals._fulfill();
          })(function() {
            if (output_iv) {
              ct = iv.clone().concat(ct);
            }
            if (_this.version.xsalsa20_rev) {
              args.key.scrub();
              args.iv.scrub();
            }
            return cb(null, ct);
          });
        };
      })(this));
    };

    Base.prototype.run_twofish = function(_arg, cb) {
      var block_cipher, ct, input, iv, key, progress_hook, ___iced_passed_deferral, __iced_deferrals, __iced_k;
      __iced_k = __iced_k_noop;
      ___iced_passed_deferral = iced.findDeferral(arguments);
      input = _arg.input, key = _arg.key, iv = _arg.iv, progress_hook = _arg.progress_hook;
      (function(_this) {
        return (function(__iced_k) {
          __iced_deferrals = new iced.Deferrals(__iced_k, {
            parent: ___iced_passed_deferral,
            filename: "/home/max/src/keybase/triplesec/src/enc.iced",
            funcname: "Base.run_twofish"
          });
          _this._check_scrubbed(key, "TwoFish", cb, __iced_deferrals.defer({
            lineno: 232
          }));
          __iced_deferrals._fulfill();
        });
      })(this)((function(_this) {
        return function() {
          block_cipher = new TwoFish(key);
          (function(__iced_k) {
            __iced_deferrals = new iced.Deferrals(__iced_k, {
              parent: ___iced_passed_deferral,
              filename: "/home/max/src/keybase/triplesec/src/enc.iced",
              funcname: "Base.run_twofish"
            });
            ctr.bulk_encrypt({
              block_cipher: block_cipher,
              iv: iv,
              input: input,
              progress_hook: progress_hook,
              what: "twofish"
            }, __iced_deferrals.defer({
              assign_fn: (function() {
                return function() {
                  return ct = arguments[0];
                };
              })(),
              lineno: 234
            }));
            __iced_deferrals._fulfill();
          })(function() {
            block_cipher.scrub();
            return cb(null, iv.clone().concat(ct));
          });
        };
      })(this));
    };

    Base.prototype.run_aes = function(_arg, cb) {
      var block_cipher, ct, input, iv, key, progress_hook, ___iced_passed_deferral, __iced_deferrals, __iced_k;
      __iced_k = __iced_k_noop;
      ___iced_passed_deferral = iced.findDeferral(arguments);
      input = _arg.input, key = _arg.key, iv = _arg.iv, progress_hook = _arg.progress_hook;
      (function(_this) {
        return (function(__iced_k) {
          __iced_deferrals = new iced.Deferrals(__iced_k, {
            parent: ___iced_passed_deferral,
            filename: "/home/max/src/keybase/triplesec/src/enc.iced",
            funcname: "Base.run_aes"
          });
          _this._check_scrubbed(key, "AES", cb, __iced_deferrals.defer({
            lineno: 249
          }));
          __iced_deferrals._fulfill();
        });
      })(this)((function(_this) {
        return function() {
          block_cipher = new AES(key);
          (function(__iced_k) {
            __iced_deferrals = new iced.Deferrals(__iced_k, {
              parent: ___iced_passed_deferral,
              filename: "/home/max/src/keybase/triplesec/src/enc.iced",
              funcname: "Base.run_aes"
            });
            ctr.bulk_encrypt({
              block_cipher: block_cipher,
              iv: iv,
              input: input,
              progress_hook: progress_hook,
              what: "aes"
            }, __iced_deferrals.defer({
              assign_fn: (function() {
                return function() {
                  return ct = arguments[0];
                };
              })(),
              lineno: 251
            }));
            __iced_deferrals._fulfill();
          })(function() {
            block_cipher.scrub();
            return cb(null, iv.clone().concat(ct));
          });
        };
      })(this));
    };

    Base.prototype.scrub = function() {
      var key, key_ring, salt, _i, _len, _ref1;
      if (this.key != null) {
        this.key.scrub();
      }
      if (this.derived_keys != null) {
        _ref1 = this.derived_keys;
        for (salt in _ref1) {
          key_ring = _ref1[salt];
          for (_i = 0, _len = key_ring.length; _i < _len; _i++) {
            key = key_ring[_i];
            key.scrub();
          }
        }
      }
      this.derived_keys = {};
      if (this.salt != null) {
        this.salt.scrub();
      }
      this.salt = null;
      return this.key = null;
    };

    return Base;

  })();

  Encryptor = (function(_super) {
    __extends(Encryptor, _super);

    function Encryptor(_arg) {
      var key, rng, version;
      key = _arg.key, rng = _arg.rng, version = _arg.version;
      Encryptor.__super__.constructor.call(this, {
        key: key,
        version: version
      });
      this.rng = rng || prng.generate;
    }

    Encryptor.prototype.pick_random_ivs = function(_arg, cb) {
      var iv_lens, ivs, k, progress_hook, v, ___iced_passed_deferral, __iced_deferrals, __iced_k;
      __iced_k = __iced_k_noop;
      ___iced_passed_deferral = iced.findDeferral(arguments);
      progress_hook = _arg.progress_hook;
      iv_lens = {
        aes: AES.ivSize,
        twofish: TwoFish.ivSize,
        salsa20: salsa20.Salsa20.ivSize
      };
      ivs = {};
      (function(_this) {
        return (function(__iced_k) {
          var _i, _k, _keys, _ref1, _results, _while;
          _ref1 = iv_lens;
          _keys = (function() {
            var _results1;
            _results1 = [];
            for (_k in _ref1) {
              _results1.push(_k);
            }
            return _results1;
          })();
          _i = 0;
          _results = [];
          _while = function(__iced_k) {
            var _break, _continue, _next;
            _break = function() {
              return __iced_k(_results);
            };
            _continue = function() {
              return iced.trampoline(function() {
                ++_i;
                return _while(__iced_k);
              });
            };
            _next = function(__iced_next_arg) {
              _results.push(__iced_next_arg);
              return _continue();
            };
            if (!(_i < _keys.length)) {
              return _break();
            } else {
              k = _keys[_i];
              v = _ref1[k];
              (function(__iced_k) {
                __iced_deferrals = new iced.Deferrals(__iced_k, {
                  parent: ___iced_passed_deferral,
                  filename: "/home/max/src/keybase/triplesec/src/enc.iced",
                  funcname: "Encryptor.pick_random_ivs"
                });
                _this.rng(v, __iced_deferrals.defer({
                  assign_fn: (function(__slot_1, __slot_2) {
                    return function() {
                      return __slot_1[__slot_2] = arguments[0];
                    };
                  })(ivs, k),
                  lineno: 353
                }));
                __iced_deferrals._fulfill();
              })(_next);
            }
          };
          _while(__iced_k);
        });
      })(this)((function(_this) {
        return function() {
          return cb(ivs);
        };
      })(this));
    };

    Encryptor.prototype.resalt = function(_arg, cb) {
      var err, extra_keymaterial, progress_hook, salt, ___iced_passed_deferral, __iced_deferrals, __iced_k;
      __iced_k = __iced_k_noop;
      ___iced_passed_deferral = iced.findDeferral(arguments);
      salt = _arg.salt, extra_keymaterial = _arg.extra_keymaterial, progress_hook = _arg.progress_hook;
      err = null;
      (function(_this) {
        return (function(__iced_k) {
          if (salt == null) {
            (function(__iced_k) {
              __iced_deferrals = new iced.Deferrals(__iced_k, {
                parent: ___iced_passed_deferral,
                filename: "/home/max/src/keybase/triplesec/src/enc.iced",
                funcname: "Encryptor.resalt"
              });
              _this.rng(_this.version.salt_size, __iced_deferrals.defer({
                assign_fn: (function(__slot_1) {
                  return function() {
                    return __slot_1.salt = arguments[0];
                  };
                })(_this),
                lineno: 369
              }));
              __iced_deferrals._fulfill();
            })(__iced_k);
          } else {
            return __iced_k(salt.length !== _this.version.salt_size ? err = new Error("Need a salt of exactly " + _this.version.salt_size + " bytes (got " + salt.length + ")") : _this.salt = WordArray.alloc(salt));
          }
        });
      })(this)((function(_this) {
        return function() {
          (function(__iced_k) {
            if (err == null) {
              (function(__iced_k) {
                __iced_deferrals = new iced.Deferrals(__iced_k, {
                  parent: ___iced_passed_deferral,
                  filename: "/home/max/src/keybase/triplesec/src/enc.iced",
                  funcname: "Encryptor.resalt"
                });
                _this.kdf({
                  extra_keymaterial: extra_keymaterial,
                  progress_hook: progress_hook,
                  salt: _this.salt
                }, __iced_deferrals.defer({
                  assign_fn: (function(__slot_1) {
                    return function() {
                      err = arguments[0];
                      return __slot_1.keys = arguments[1];
                    };
                  })(_this),
                  lineno: 375
                }));
                __iced_deferrals._fulfill();
              })(__iced_k);
            } else {
              return __iced_k();
            }
          })(function() {
            return cb(err, _this.keys);
          });
        };
      })(this));
    };

    Encryptor.prototype.run = function(_arg, cb) {
      var ct1, ct2, ct3, data, esc, extra_keymaterial, ivs, progress_hook, pt, ret, salt, sig, ___iced_passed_deferral, __iced_deferrals, __iced_k;
      __iced_k = __iced_k_noop;
      ___iced_passed_deferral = iced.findDeferral(arguments);
      data = _arg.data, salt = _arg.salt, extra_keymaterial = _arg.extra_keymaterial, progress_hook = _arg.progress_hook;
      esc = make_esc(cb, "Encryptor::run");
      (function(_this) {
        return (function(__iced_k) {
          if ((salt != null) || (_this.salt == null)) {
            (function(__iced_k) {
              __iced_deferrals = new iced.Deferrals(__iced_k, {
                parent: ___iced_passed_deferral,
                filename: "/home/max/src/keybase/triplesec/src/enc.iced",
                funcname: "Encryptor.run"
              });
              _this.resalt({
                salt: salt,
                extra_keymaterial: extra_keymaterial,
                progress_hook: progress_hook
              }, esc(__iced_deferrals.defer({
                lineno: 406
              })));
              __iced_deferrals._fulfill();
            })(__iced_k);
          } else {
            return __iced_k();
          }
        });
      })(this)((function(_this) {
        return function() {
          (function(__iced_k) {
            __iced_deferrals = new iced.Deferrals(__iced_k, {
              parent: ___iced_passed_deferral,
              filename: "/home/max/src/keybase/triplesec/src/enc.iced",
              funcname: "Encryptor.run"
            });
            _this.pick_random_ivs({
              progress_hook: progress_hook
            }, __iced_deferrals.defer({
              assign_fn: (function() {
                return function() {
                  return ivs = arguments[0];
                };
              })(),
              lineno: 407
            }));
            __iced_deferrals._fulfill();
          })(function() {
            pt = WordArray.from_buffer(data);
            (function(__iced_k) {
              __iced_deferrals = new iced.Deferrals(__iced_k, {
                parent: ___iced_passed_deferral,
                filename: "/home/max/src/keybase/triplesec/src/enc.iced",
                funcname: "Encryptor.run"
              });
              _this.run_salsa20({
                input: pt,
                key: _this.keys.salsa20,
                progress_hook: progress_hook,
                iv: ivs.salsa20,
                output_iv: true
              }, esc(__iced_deferrals.defer({
                assign_fn: (function() {
                  return function() {
                    return ct1 = arguments[0];
                  };
                })(),
                lineno: 409
              })));
              __iced_deferrals._fulfill();
            })(function() {
              (function(__iced_k) {
                __iced_deferrals = new iced.Deferrals(__iced_k, {
                  parent: ___iced_passed_deferral,
                  filename: "/home/max/src/keybase/triplesec/src/enc.iced",
                  funcname: "Encryptor.run"
                });
                _this.run_twofish({
                  input: ct1,
                  key: _this.keys.twofish,
                  progress_hook: progress_hook,
                  iv: ivs.twofish
                }, esc(__iced_deferrals.defer({
                  assign_fn: (function() {
                    return function() {
                      return ct2 = arguments[0];
                    };
                  })(),
                  lineno: 410
                })));
                __iced_deferrals._fulfill();
              })(function() {
                (function(__iced_k) {
                  __iced_deferrals = new iced.Deferrals(__iced_k, {
                    parent: ___iced_passed_deferral,
                    filename: "/home/max/src/keybase/triplesec/src/enc.iced",
                    funcname: "Encryptor.run"
                  });
                  _this.run_aes({
                    input: ct2,
                    key: _this.keys.aes,
                    progress_hook: progress_hook,
                    iv: ivs.aes
                  }, esc(__iced_deferrals.defer({
                    assign_fn: (function() {
                      return function() {
                        return ct3 = arguments[0];
                      };
                    })(),
                    lineno: 411
                  })));
                  __iced_deferrals._fulfill();
                })(function() {
                  (function(__iced_k) {
                    __iced_deferrals = new iced.Deferrals(__iced_k, {
                      parent: ___iced_passed_deferral,
                      filename: "/home/max/src/keybase/triplesec/src/enc.iced",
                      funcname: "Encryptor.run"
                    });
                    _this.sign({
                      input: ct3,
                      key: _this.keys.hmac,
                      progress_hook: progress_hook,
                      salt: _this.salt
                    }, esc(__iced_deferrals.defer({
                      assign_fn: (function() {
                        return function() {
                          return sig = arguments[0];
                        };
                      })(),
                      lineno: 412
                    })));
                    __iced_deferrals._fulfill();
                  })(function() {
                    ret = (new WordArray(_this.version.header)).concat(_this.salt).concat(sig).concat(ct3).to_buffer();
                    util.scrub_buffer(data);
                    return cb(null, ret);
                  });
                });
              });
            });
          });
        };
      })(this));
    };

    return Encryptor;

  })(Base);

  encrypt = function(_arg, cb) {
    var data, enc, err, key, progress_hook, ret, rng, version, ___iced_passed_deferral, __iced_deferrals, __iced_k;
    __iced_k = __iced_k_noop;
    ___iced_passed_deferral = iced.findDeferral(arguments);
    key = _arg.key, data = _arg.data, rng = _arg.rng, progress_hook = _arg.progress_hook, version = _arg.version;
    enc = new Encryptor({
      key: key,
      rng: rng,
      version: version
    });
    (function(_this) {
      return (function(__iced_k) {
        __iced_deferrals = new iced.Deferrals(__iced_k, {
          parent: ___iced_passed_deferral,
          filename: "/home/max/src/keybase/triplesec/src/enc.iced"
        });
        enc.run({
          data: data,
          progress_hook: progress_hook
        }, __iced_deferrals.defer({
          assign_fn: (function() {
            return function() {
              err = arguments[0];
              return ret = arguments[1];
            };
          })(),
          lineno: 440
        }));
        __iced_deferrals._fulfill();
      });
    })(this)((function(_this) {
      return function() {
        enc.scrub();
        return cb(err, ret);
      };
    })(this));
  };

  exports.V = V;

  exports.encrypt = encrypt;

  exports.Base = Base;

  exports.Encryptor = Encryptor;

}).call(this);
