diff options
Diffstat (limited to 'libjava/classpath/gnu/java/security/sig/rsa/EME_PKCS1_V1_5.java')
-rw-r--r-- | libjava/classpath/gnu/java/security/sig/rsa/EME_PKCS1_V1_5.java | 274 |
1 files changed, 274 insertions, 0 deletions
diff --git a/libjava/classpath/gnu/java/security/sig/rsa/EME_PKCS1_V1_5.java b/libjava/classpath/gnu/java/security/sig/rsa/EME_PKCS1_V1_5.java new file mode 100644 index 000000000..329ca8ed6 --- /dev/null +++ b/libjava/classpath/gnu/java/security/sig/rsa/EME_PKCS1_V1_5.java @@ -0,0 +1,274 @@ +/* EME_PKCS1_V1_5.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.sig.rsa; + +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.util.PRNG; + +import java.io.ByteArrayOutputStream; +import java.security.interfaces.RSAKey; +import java.util.Random; + +/** + * An implementation of the EME-PKCS1-V1.5 encoding and decoding methods. + * <p> + * EME-PKCS1-V1.5 is parameterised by the entity <code>k</code> which is the + * byte count of an RSA public shared modulus. + * <p> + * References: + * <ol> + * <li><a href="http://www.ietf.org/rfc/rfc3447.txt">Public-Key Cryptography + * Standards (PKCS) #1:</a><br> + * RSA Cryptography Specifications Version 2.1.<br> + * Jakob Jonsson and Burt Kaliski.</li> + * </ol> + */ +public class EME_PKCS1_V1_5 +{ + private int k; + + private ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + /** Our default source of randomness. */ + private PRNG prng = PRNG.getInstance(); + + private EME_PKCS1_V1_5(final int k) + { + super(); + + this.k = k; + } + + public static final EME_PKCS1_V1_5 getInstance(final int k) + { + if (k < 0) + throw new IllegalArgumentException("k must be a positive integer"); + + return new EME_PKCS1_V1_5(k); + } + + public static final EME_PKCS1_V1_5 getInstance(final RSAKey key) + { + final int modBits = key.getModulus().bitLength(); + final int k = (modBits + 7) / 8; + return EME_PKCS1_V1_5.getInstance(k); + } + + /** + * Generates an octet string <code>PS</code> of length <code>k - mLen - + * 3</code> consisting of pseudo-randomly generated nonzero octets. The length + * of <code>PS</code> will be at least eight octets. + * <p> + * The method then concatenates <code>PS</code>, the message <code>M</code>, + * and other padding to form an encoded message <code>EM</code> of length + * <code>k</code> octets as: + * <pre> + * EM = 0x00 || 0x02 || PS || 0x00 || M. + * </pre> + * <p> + * This method uses a default PRNG to obtain the padding bytes. + * + * @param M the message to encode. + * @return the encoded message <code>EM</code>. + */ + public byte[] encode(final byte[] M) + { + // a. Generate an octet string PS of length k - mLen - 3 consisting + // of pseudo-randomly generated nonzero octets. The length of PS + // will be at least eight octets. + final byte[] PS = new byte[k - M.length - 3]; + // FIXME. This should be configurable, somehow. + prng.nextBytes(PS); + int i = 0; + for (; i < PS.length; i++) + { + if (PS[i] == 0) + PS[i] = 1; + } + // b. Concatenate PS, the message M, and other padding to form an + // encoded message EM of length k octets as + // + // EM = 0x00 || 0x02 || PS || 0x00 || M. + return assembleEM(PS, M); + } + + /** + * Similar to {@link #encode(byte[])} method, except that the source of + * randomness to use for obtaining the padding bytes (an instance of + * {@link IRandom}) is given as a parameter. + * + * @param M the message to encode. + * @param irnd the {@link IRandom} instance to use as a source of randomness. + * @return the encoded message <code>EM</code>. + */ + public byte[] encode(final byte[] M, final IRandom irnd) + { + final byte[] PS = new byte[k - M.length - 3]; + try + { + irnd.nextBytes(PS, 0, PS.length); + int i = 0; + outer: while (true) + { + for (; i < PS.length; i++) + { + if (PS[i] == 0x00) + { + System.arraycopy(PS, i + 1, PS, i, PS.length - i - 1); + irnd.nextBytes(PS, PS.length - 1, 1); + continue outer; + } + } + break; + } + } + catch (IllegalStateException x) + { + throw new RuntimeException("encode(): " + String.valueOf(x)); + } + catch (LimitReachedException x) + { + throw new RuntimeException("encode(): " + String.valueOf(x)); + } + return assembleEM(PS, M); + } + + /** + * Similar to the {@link #encode(byte[], IRandom)} method, except that the + * source of randmoness is an instance of {@link Random}. + * + * @param M the message to encode. + * @param rnd the {@link Random} instance to use as a source of randomness. + * @return the encoded message <code>EM</code>. + */ + public byte[] encode(final byte[] M, final Random rnd) + { + final byte[] PS = new byte[k - M.length - 3]; + rnd.nextBytes(PS); + int i = 0; + outer: while (true) + { + for (; i < PS.length; i++) + { + if (PS[i] == 0x00) + { + System.arraycopy(PS, i + 1, PS, i, PS.length - i - 1); + PS[PS.length - 1] = (byte) rnd.nextInt(); + continue outer; + } + } + break; + } + return assembleEM(PS, M); + } + + /** + * Separate the encoded message <code>EM</code> into an octet string + * <code>PS</code> consisting of nonzero octets and a message <code>M</code> + * as: + * <pre> + * EM = 0x00 || 0x02 || PS || 0x00 || M. + * </pre> + * <p> + * If the first octet of <code>EM</code> does not have hexadecimal value + * <code>0x00</code>, if the second octet of <code>EM</code> does not + * have hexadecimal value <code>0x02</code>, if there is no octet with + * hexadecimal value <code>0x00</code> to separate <code>PS</code> from + * <code>M</code>, or if the length of <code>PS</code> is less than + * <code>8</code> octets, output "decryption error" and stop. + * + * @param EM the designated encoded message. + * @return the decoded message <code>M</code> framed in the designated + * <code>EM</code> value. + * @throws IllegalArgumentException if the length of the designated entity + * <code>EM</code> is different than <code>k</code> (the length + * in bytes of the public shared modulus), or if any of the + * conditions described above is detected. + */ + public byte[] decode(final byte[] EM) + { + // Separate the encoded message EM into an + // octet string PS consisting of nonzero octets and a message M as + // + // EM = 0x00 || 0x02 || PS || 0x00 || M. + // + // If the first octet of EM does not have hexadecimal value 0x00, if + // the second octet of EM does not have hexadecimal value 0x02, if + // there is no octet with hexadecimal value 0x00 to separate PS from + // M, or if the length of PS is less than 8 octets, output + // "decryption error" and stop. (See the note below.) + final int emLen = EM.length; + if (emLen != k) + throw new IllegalArgumentException("decryption error"); + if (EM[0] != 0x00) + throw new IllegalArgumentException("decryption error"); + if (EM[1] != 0x02) + throw new IllegalArgumentException("decryption error"); + int i = 2; + for (; i < emLen; i++) + { + if (EM[i] == 0x00) + break; + } + if (i >= emLen || i < 11) + throw new IllegalArgumentException("decryption error"); + i++; + final byte[] result = new byte[emLen - i]; + System.arraycopy(EM, i, result, 0, result.length); + return result; + } + + private byte[] assembleEM(final byte[] PS, final byte[] M) + { + // b. Concatenate PS, the message M, and other padding to form an + // encoded message EM of length k octets as + // + // EM = 0x00 || 0x02 || PS || 0x00 || M. + baos.reset(); + baos.write(0x00); + baos.write(0x02); + baos.write(PS, 0, PS.length); + baos.write(0x00); + baos.write(M, 0, M.length); + final byte[] result = baos.toByteArray(); + baos.reset(); + return result; + } +} |