summaryrefslogtreecommitdiff
path: root/src/org/noreply/fancydress/crypto/RSAPublicKey.java
blob: 13f8b53aee343fcb09e3e3eb685c30ec0434da2a (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
package org.noreply.fancydress.crypto;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
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;

	/**
	 * Construct an instance of an RSAPublicKey from the ASN1 encoded key.
	 *
	 * @param asnEncoded ASN1 encoded RSA key.
	 */
	public RSAPublicKey(byte[] asnEncoded) {
		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(), CryptoPrimitives.hash(Util.toOctets(p)));

		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());
	};
	/**
	 * 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);
	}
}