summaryrefslogtreecommitdiff
path: root/src/org/noreply/fancydress/crypto/RSAPublicKey.java
blob: 5e096094768a7a15e4803c990f83bf9b0de5c4cd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/* $Id$ */
package org.noreply.fancydress.crypto;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DERInputStream;
import org.bouncycastle.asn1.x509.RSAPublicKeyStructure;
import org.bouncycastle.crypto.AsymmetricBlockCipher;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.engines.RSAEngine;
import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.crypto.encodings.OAEPEncoding;
import org.bouncycastle.crypto.params.RSAKeyParameters;
import org.noreply.fancydress.misc.Util;

/**
 * This class is a wrapper for the bouncycastle RSA functionality.
 */
public class RSAPublicKey {
	/**
	 * The overhead (in octets) added by OAEP padding.
	 */
	public static final int PK_OVERHEAD_LEN = 42;
	/**
	 * The length of encrypted data. (we use 2048 bit keys)
	 */
	public static final int PK_ENC_LEN = 256;
	/**
	 * The maximum amount of octets that can be encoded in an RSA message.
	 */
	public static final int PK_MAX_DATA_LEN = PK_ENC_LEN - PK_OVERHEAD_LEN;

	/**
	 * the RSA cipher from bouncycastle.
	 */
	private AsymmetricBlockCipher rsa_cipher;
	/**
	 * a key structure
	 */
	private RSAPublicKeyStructure key;
	/**
	 * key parameters
	 */
	private RSAKeyParameters keyParams;

	/**
	 * initialize rsa cipher.
	 */
	private void init() {
		String p   = new String("He who would make his own liberty secure, must guard even his enemy from oppression.");
		rsa_cipher = new OAEPEncoding(new RSAEngine(), new SHA1Digest(), Util.toOctets(p));

	}

	/**
	 * Construct an instance of an RSAPublicKey from the ASN1 encoded key.
	 *
	 * @param asnEncoded ASN1 encoded RSA key.
	 */
	public RSAPublicKey(byte[] asnEncoded) {
		init();
		ByteArrayInputStream     bIn = new ByteArrayInputStream(asnEncoded);
		DERInputStream           dIn = new DERInputStream(bIn);
		try {
			key                  = new RSAPublicKeyStructure((ASN1Sequence)dIn.readObject());
		} catch (IOException e) {
			throw new Error(e);
		}
		keyParams                    = new RSAKeyParameters(false, key.getModulus(), key.getPublicExponent());
	};
	/**
	 * Construct an instance of an RSAPublicKey from the modulus and public exponend.
	 *
	 * @param modulus Modulus of the key
	 * @param exponent public exponend of the key
	 */
	public RSAPublicKey(BigInteger modulus, BigInteger exponent) {
		init();
		keyParams                    = new RSAKeyParameters(false, modulus, exponent);
		key                          = new RSAPublicKeyStructure(modulus, exponent);
	};

	/**
	 * Encrypt a message.
	 *
	 * Encrypts message m to this key.
	 * 
	 * @param m the message to encrypt.
	 * @return the encrypted message (PK_ENC_LEN octets long)
	 */
	public byte[] encrypt(byte[] m) {
		rsa_cipher.init(true, keyParams);
		byte[] result;
		try {
			result = rsa_cipher.processBlock(m, 0, m.length);
		} catch (InvalidCipherTextException e) {
			throw new Error(e);
		}
		return(result);
	}
	/**
	 * Verify a signature.
	 *
	 * Verify that the information signed in signature <code>sig</code>
	 * matches the value in <code>m</code>.
	 *
	 * @param sig the signature
	 * @param m message to compare the signed information to
	 * @return true if the signature is valid
	 * @throws InvalidCipherTextException
	 */
	public boolean verify(byte[] sig, byte[] m) throws InvalidCipherTextException {
		rsa_cipher.init(false, keyParams);
		byte[] signedDigest = rsa_cipher.processBlock(sig, 0, sig.length);
		byte[] digest = CryptoPrimitives.hash(m);
		boolean verifies = Util.equal(digest, signedDigest);
		return(verifies);
	}
	/**
	 * Return the ASN 1 encoding of this key.
	 *
	 * @return this key, asn1 encoded
	 */
	public byte[] encode() {
		DEROctetString asn = new DEROctetString(key);
		byte[] result = asn.getOctets();
		return(result);
	}
	/**
	 * Get this key's fingerprint.
	 *
	 * The fingerprint (or keyid) is the hash of the asn1 representation of this key.
	 *
	 * @return the fingerprint.
	 */
	public byte[] getFingerprint() {
		DEROctetString asn = new DEROctetString(key);
		byte[] encoded = asn.getOctets();
		byte[] result = CryptoPrimitives.hash(encoded);
		return(result);
	}
}