<?php

namespace Leenooks\OpenPGP;

/**
 * OpenPGP Secret-Key packet (tag 5).
 *
 * @see http://tools.ietf.org/html/rfc4880#section-5.5.1.3
 * @see http://tools.ietf.org/html/rfc4880#section-5.5.3
 * @see http://tools.ietf.org/html/rfc4880#section-11.2
 * @see http://tools.ietf.org/html/rfc4880#section-12
 */
class SecretKeyPacket extends PublicKeyPacket
{
	protected $tag = 5;
	public $s2k_useage, $s2k, $symmetric_algorithm, $private_hash, $encrypted_data;

	static $secret_key_fields = array(
		1 => array('d', 'p', 'q', 'u'), // RSA
		2 => array('d', 'p', 'q', 'u'), // RSA-E
		3 => array('d', 'p', 'q', 'u'), // RSA-S
		16 => array('x'),                // ELG-E
		17 => array('x'),                // DSA
	);

	function body()
	{
		$bytes = parent::body() . chr($this->s2k_useage);
		$secret_material = NULL;
		if($this->s2k_useage == 255 || $this->s2k_useage == 254) {
			$bytes .= chr($this->symmetric_algorithm);
			$bytes .= $this->s2k->to_bytes();
		}
		if($this->s2k_useage > 0) {
			$bytes .= $this->encrypted_data;
		} else {
			$secret_material = '';
			foreach(self::$secret_key_fields[$this->algorithm] as $f) {
				$f = $this->key[$f];
				$secret_material .= pack('n', \Leenooks\OpenPGP::bitlength($f));
				$secret_material .= $f;
			}
			$bytes .= $secret_material;

			// 2-octet checksum
			$chk = 0;
			for($i = 0; $i < strlen($secret_material); $i++) {
				$chk = ($chk + ord($secret_material[$i])) % 65536;
			}
			$bytes .= pack('n', $chk);
		}
		return $bytes;
	}

	function key_from_input()
	{
		foreach(self::$secret_key_fields[$this->algorithm] as $field) {
			$this->key[$field] = $this->read_mpi();
		}
	}

	function read()
	{
		parent::read(); // All the fields from PublicKey

		$this->s2k_useage = ord($this->read_byte());
		if($this->s2k_useage == 255 || $this->s2k_useage == 254) {
			$this->symmetric_algorithm = ord($this->read_byte());
			$this->s2k = S2K::parse($this->input);
		} else if($this->s2k_useage > 0) {
			$this->symmetric_algorithm = $this->s2k_useage;
		}
		if($this->s2k_useage > 0) {
			$this->encrypted_data = $this->input; // Rest of input is MPIs and checksum (encrypted)
		} else {
			$this->key_from_input();
			$this->private_hash = $this->read_bytes(2); // TODO: Validate checksum?
		}
	}
}