001: // Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
002:
003: package org.xbill.DNS.security;
004:
005: import java.io.*;
006: import java.math.*;
007: import java.security.*;
008: import java.security.interfaces.*;
009: import javax.crypto.interfaces.*;
010: import org.xbill.DNS.*;
011: import org.xbill.DNS.utils.*;
012:
013: /**
014: * Routines to convert between a DNS KEY record and a Java PublicKey.
015: *
016: * @author Brian Wellington
017: */
018:
019: public class KEYConverter {
020:
021: private static final BigInteger DHPRIME768 = new BigInteger(
022: "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF",
023: 16);
024: private static final BigInteger DHPRIME1024 = new BigInteger(
025: "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF",
026: 16);
027: private static final BigInteger TWO = new BigInteger("2", 16);
028:
029: static int BigIntegerLength(BigInteger i) {
030: byte[] b = i.toByteArray();
031: return (b[0] == 0 ? b.length - 1 : b.length);
032: }
033:
034: static BigInteger readBigInteger(DataInputStream in, int len)
035: throws IOException {
036: byte[] b = new byte[len];
037: int n = in.read(b);
038: if (n < len)
039: throw new IOException("end of input");
040: return new BigInteger(1, b);
041: }
042:
043: static void writeBigInteger(ByteArrayOutputStream out,
044: BigInteger val) {
045: byte[] b = val.toByteArray();
046: if (b[0] == 0)
047: out.write(b, 1, b.length - 1);
048: else
049: out.write(b, 0, b.length);
050: }
051:
052: static void writeShort(ByteArrayOutputStream out, int i) {
053: out.write((i >> 8) & 0xFF);
054: out.write(i & 0xFF);
055: }
056:
057: static RSAPublicKey parseRSA(DataInputStream in) throws IOException {
058: int exponentLength = in.readUnsignedByte();
059: if (exponentLength == 0)
060: exponentLength = in.readUnsignedShort();
061: BigInteger exponent = readBigInteger(in, exponentLength);
062:
063: int modulusLength = in.available();
064: BigInteger modulus = readBigInteger(in, modulusLength);
065:
066: RSAPublicKey rsa = new RSAPubKey(modulus, exponent);
067: return rsa;
068: }
069:
070: static DHPublicKey parseDH(DataInputStream in) throws IOException {
071: int special = 0;
072: int pLength = in.readUnsignedShort();
073: if (pLength < 16 && pLength != 1 && pLength != 2)
074: return null;
075: BigInteger p;
076: if (pLength == 1 || pLength == 2) {
077: if (pLength == 1)
078: special = in.readUnsignedByte();
079: else
080: special = in.readUnsignedShort();
081: if (special != 1 && special != 2)
082: return null;
083: if (special == 1)
084: p = DHPRIME768;
085: else
086: p = DHPRIME1024;
087: } else
088: p = readBigInteger(in, pLength);
089:
090: int gLength = in.readUnsignedShort();
091: BigInteger g;
092: if (gLength == 0) {
093: if (special != 0)
094: g = TWO;
095: else
096: return null;
097: } else
098: g = readBigInteger(in, gLength);
099:
100: int yLength = in.readUnsignedShort();
101: BigInteger y = readBigInteger(in, yLength);
102:
103: return new DHPubKey(p, g, y);
104: }
105:
106: static DSAPublicKey parseDSA(DataInputStream in) throws IOException {
107: byte t = in.readByte();
108:
109: BigInteger q = readBigInteger(in, 20);
110: BigInteger p = readBigInteger(in, 64 + t * 8);
111: BigInteger g = readBigInteger(in, 64 + t * 8);
112: BigInteger y = readBigInteger(in, 64 + t * 8);
113:
114: DSAPublicKey dsa = new DSAPubKey(p, q, g, y);
115: return dsa;
116: }
117:
118: /** Converts a KEY/DNSKEY record into a PublicKey */
119: static PublicKey parseRecord(int alg, byte[] data) {
120: ByteArrayInputStream bytes = new ByteArrayInputStream(data);
121: DataInputStream in = new DataInputStream(bytes);
122: try {
123: switch (alg) {
124: case DNSSEC.RSAMD5:
125: case DNSSEC.RSASHA1:
126: return parseRSA(in);
127: case DNSSEC.DH:
128: return parseDH(in);
129: case DNSSEC.DSA:
130: return parseDSA(in);
131: default:
132: return null;
133: }
134: } catch (IOException e) {
135: if (Options.check("verboseexceptions"))
136: System.err.println(e);
137: return null;
138: }
139: }
140:
141: /** Converts a DNSKEY record into a PublicKey */
142: public static PublicKey parseRecord(DNSKEYRecord r) {
143: int alg = r.getAlgorithm();
144: byte[] data = r.getKey();
145: return parseRecord(alg, data);
146: }
147:
148: /** Converts a KEY record into a PublicKey */
149: public static PublicKey parseRecord(KEYRecord r) {
150: int alg = r.getAlgorithm();
151: byte[] data = r.getKey();
152: return parseRecord(alg, data);
153: }
154:
155: static byte[] buildRSA(RSAPublicKey key) {
156: ByteArrayOutputStream out = new ByteArrayOutputStream();
157: BigInteger exponent = key.getPublicExponent();
158: BigInteger modulus = key.getModulus();
159: int exponentLength = BigIntegerLength(exponent);
160:
161: if (exponentLength < 256)
162: out.write(exponentLength);
163: else {
164: out.write(0);
165: writeShort(out, exponentLength);
166: }
167: writeBigInteger(out, exponent);
168: writeBigInteger(out, modulus);
169:
170: return out.toByteArray();
171: }
172:
173: static byte[] buildDH(DHPublicKey key) {
174: ByteArrayOutputStream out = new ByteArrayOutputStream();
175: BigInteger p = key.getParams().getP();
176: BigInteger g = key.getParams().getG();
177: BigInteger y = key.getY();
178:
179: int pLength, gLength, yLength;
180: if (g.equals(TWO)
181: && (p.equals(DHPRIME768) || p.equals(DHPRIME1024))) {
182: pLength = 1;
183: gLength = 0;
184: } else {
185: pLength = BigIntegerLength(p);
186: gLength = BigIntegerLength(g);
187: }
188: yLength = BigIntegerLength(y);
189:
190: writeShort(out, pLength);
191: if (pLength == 1) {
192: if (p.bitLength() == 768)
193: out.write(1);
194: else
195: out.write(2);
196: } else
197: writeBigInteger(out, p);
198: writeShort(out, gLength);
199: if (gLength > 0)
200: writeBigInteger(out, g);
201: writeShort(out, yLength);
202: writeBigInteger(out, y);
203:
204: return out.toByteArray();
205: }
206:
207: static byte[] buildDSA(DSAPublicKey key) {
208: ByteArrayOutputStream out = new ByteArrayOutputStream();
209: BigInteger q = key.getParams().getQ();
210: BigInteger p = key.getParams().getP();
211: BigInteger g = key.getParams().getG();
212: BigInteger y = key.getY();
213: int t = (p.toByteArray().length - 64) / 8;
214:
215: out.write(t);
216: writeBigInteger(out, q);
217: writeBigInteger(out, p);
218: writeBigInteger(out, g);
219: writeBigInteger(out, y);
220:
221: return out.toByteArray();
222: }
223:
224: /** Builds a KEY record from a PublicKey */
225: public static KEYRecord buildRecord(Name name, int dclass,
226: long ttl, int flags, int proto, PublicKey key) {
227: byte alg;
228:
229: if (key instanceof RSAPublicKey) {
230: alg = DNSSEC.RSAMD5;
231: } else if (key instanceof DHPublicKey) {
232: alg = DNSSEC.DH;
233: } else if (key instanceof DSAPublicKey) {
234: alg = DNSSEC.DSA;
235: } else
236: return null;
237:
238: return (KEYRecord) buildRecord(name, Type.KEY, dclass, ttl,
239: flags, proto, alg, key);
240: }
241:
242: /** Builds a DNSKEY or KEY record from a PublicKey */
243: public static Record buildRecord(Name name, int type, int dclass,
244: long ttl, int flags, int proto, int alg, PublicKey key) {
245: byte[] data;
246:
247: if (type != Type.KEY && type != Type.DNSKEY)
248: throw new IllegalArgumentException("type must be KEY "
249: + "or DNSKEY");
250:
251: if (key instanceof RSAPublicKey) {
252: data = buildRSA((RSAPublicKey) key);
253: } else if (key instanceof DHPublicKey) {
254: data = buildDH((DHPublicKey) key);
255: } else if (key instanceof DSAPublicKey) {
256: data = buildDSA((DSAPublicKey) key);
257: } else
258: return null;
259:
260: if (data == null)
261: return null;
262:
263: if (type == Type.DNSKEY)
264: return new DNSKEYRecord(name, dclass, ttl, flags, proto,
265: alg, data);
266: else
267: return new KEYRecord(name, dclass, ttl, flags, proto, alg,
268: data);
269: }
270:
271: }
|