// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)

package org.xbill.DNS.security;

import java.security.SignatureException;
import java.security.interfaces.DSAParams;
import java.util.Arrays;
import org.xbill.DNS.*;

/**
 * Converts DSA signatures between the SIG record format (as specified
 * in RFC 2536) and the format used by Java DSA routines (DER-encoded).
 *
 * @author Brian Wellington
 */

public class DSASignature {

static final int ASN1_SEQ = 0x30;
static final int ASN1_INT = 0x2;

private DSASignature() {}

/**
 * Converts the signature field in a SIG record to the
 * format expected by the DSA verification routines.
 */
static byte []
create(SIGRecord sigrec) {
	final int len = 20;
	int n = 0;
	byte rlen, slen, seqlen;

	byte [] sigdata = sigrec.getSignature();

	rlen = len;
	if (sigdata[1] < 0)
		rlen++;

	slen = len;
	if (sigdata[1] < 0)
		slen++;

	/* 4 = 2 * (INT, value) */
	seqlen = (byte) (rlen + slen + 4);

	/* 2 = 1 * (SEQ, value) */
	byte [] array = new byte[seqlen + 2];

	array[n++] = ASN1_SEQ;
	array[n++] = (byte) seqlen;
	array[n++] = ASN1_INT;
	array[n++] = rlen;
	if (rlen > len)
		array[n++] = 0;
	for (int i = 0; i < len; i++, n++)
		array[n] = sigdata[1 + i];
	array[n++] = ASN1_INT;
	array[n++] = slen;
	if (slen > len)
		array[n++] = 0;
	for (int i = 0; i < len; i++, n++)
		array[n] = sigdata[1 + len + i];
	return array;
}

/**
 * Converts the signature generated by DSA signature routines to
 * the one expected inside a SIG record.
 */
static byte []
create(DSAParams params, byte [] sig)
throws SignatureException
{
	int rLength, sLength;
	int rOffset, sOffset;
	if ((sig[0] != ASN1_SEQ) || (sig[2] != ASN1_INT))
		throw new SignatureException("Expected SEQ, INT");
	rLength = sig[3];
	rOffset = 4;
	if (sig[rOffset] == 0) {
		rLength--;
		rOffset++;
	}
	if (sig[rOffset+rLength] != ASN1_INT)
		throw new SignatureException("Expected INT");
	sLength = sig[rOffset + rLength + 1];
	sOffset = rOffset + rLength + 2;
	if (sig[sOffset] == 0) {
		sLength--;
		sOffset++;
	}

	if ((rLength > 20) || (sLength > 20))
		throw new SignatureException("DSA R/S too long");

	byte[] newSig = new byte[41];
	Arrays.fill(newSig, (byte) 0);
	newSig[0] = (byte) ((params.getP().bitLength() - 512)/64);
	System.arraycopy(sig, rOffset, newSig, 1 + (20 - rLength), rLength);
	System.arraycopy(sig, sOffset, newSig, 21 + (20 - sLength), sLength);
	return newSig;
}
    
}

