'use strict';

var asn1 = require('./asn1');
var aesid = require('./aesid.json');
var fixProc = require('./fixProc');
var ciphers = require('browserify-aes');
var compat = require('pbkdf2');
var Buffer = require('safe-buffer').Buffer;

function decrypt(data, password) {
	var salt = data.algorithm.decrypt.kde.kdeparams.salt;
	var iters = parseInt(data.algorithm.decrypt.kde.kdeparams.iters.toString(), 10);
	var algo = aesid[data.algorithm.decrypt.cipher.algo.join('.')];
	var iv = data.algorithm.decrypt.cipher.iv;
	var cipherText = data.subjectPrivateKey;
	var keylen = parseInt(algo.split('-')[1], 10) / 8;
	var key = compat.pbkdf2Sync(password, salt, iters, keylen, 'sha1');
	var cipher = ciphers.createDecipheriv(algo, key, iv);
	var out = [];
	out.push(cipher.update(cipherText));
	out.push(cipher['final']());
	return Buffer.concat(out);
}

function parseKeys(buffer) {
	var password;
	if (typeof buffer === 'object' && !Buffer.isBuffer(buffer)) {
		password = buffer.passphrase;
		buffer = buffer.key;
	}
	if (typeof buffer === 'string') {
		buffer = Buffer.from(buffer);
	}

	var stripped = fixProc(buffer, password);

	var type = stripped.tag;
	var data = stripped.data;
	var subtype, ndata;
	switch (type) {
		case 'CERTIFICATE':
			ndata = asn1.certificate.decode(data, 'der').tbsCertificate.subjectPublicKeyInfo;
			// falls through
		case 'PUBLIC KEY':
			if (!ndata) {
				ndata = asn1.PublicKey.decode(data, 'der');
			}
			subtype = ndata.algorithm.algorithm.join('.');
			switch (subtype) {
				case '1.2.840.113549.1.1.1':
					return asn1.RSAPublicKey.decode(ndata.subjectPublicKey.data, 'der');
				case '1.2.840.10045.2.1':
					ndata.subjectPrivateKey = ndata.subjectPublicKey;
					return {
						type: 'ec',
						data: ndata
					};
				case '1.2.840.10040.4.1':
					ndata.algorithm.params.pub_key = asn1.DSAparam.decode(ndata.subjectPublicKey.data, 'der');
					return {
						type: 'dsa',
						data: ndata.algorithm.params
					};
				default: throw new Error('unknown key id ' + subtype);
			}
			// throw new Error('unknown key type ' + type)
		case 'ENCRYPTED PRIVATE KEY':
			data = asn1.EncryptedPrivateKey.decode(data, 'der');
			data = decrypt(data, password);
			// falls through
		case 'PRIVATE KEY':
			ndata = asn1.PrivateKey.decode(data, 'der');
			subtype = ndata.algorithm.algorithm.join('.');
			switch (subtype) {
				case '1.2.840.113549.1.1.1':
					return asn1.RSAPrivateKey.decode(ndata.subjectPrivateKey, 'der');
				case '1.2.840.10045.2.1':
					return {
						curve: ndata.algorithm.curve,
						privateKey: asn1.ECPrivateKey.decode(ndata.subjectPrivateKey, 'der').privateKey
					};
				case '1.2.840.10040.4.1':
					ndata.algorithm.params.priv_key = asn1.DSAparam.decode(ndata.subjectPrivateKey, 'der');
					return {
						type: 'dsa',
						params: ndata.algorithm.params
					};
				default: throw new Error('unknown key id ' + subtype);
			}
			// throw new Error('unknown key type ' + type)
		case 'RSA PUBLIC KEY':
			return asn1.RSAPublicKey.decode(data, 'der');
		case 'RSA PRIVATE KEY':
			return asn1.RSAPrivateKey.decode(data, 'der');
		case 'DSA PRIVATE KEY':
			return {
				type: 'dsa',
				params: asn1.DSAPrivateKey.decode(data, 'der')
			};
		case 'EC PRIVATE KEY':
			data = asn1.ECPrivateKey.decode(data, 'der');
			return {
				curve: data.parameters.value,
				privateKey: data.privateKey
			};
		default: throw new Error('unknown key type ' + type);
	}
}
parseKeys.signature = asn1.signature;

module.exports = parseKeys;
