Frames | No Frames |
1: /* EME_PKCS1_V1_5.java -- 2: Copyright (C) 2003, 2006 Free Software Foundation, Inc. 3: 4: This file is a part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2 of the License, or (at 9: your option) any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; if not, write to the Free Software 18: Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 19: USA 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: 39: package gnu.java.security.sig.rsa; 40: 41: import gnu.java.security.prng.IRandom; 42: import gnu.java.security.prng.LimitReachedException; 43: import gnu.java.security.util.PRNG; 44: 45: import java.io.ByteArrayOutputStream; 46: import java.security.interfaces.RSAKey; 47: import java.util.Random; 48: 49: /** 50: * An implementation of the EME-PKCS1-V1.5 encoding and decoding methods. 51: * <p> 52: * EME-PKCS1-V1.5 is parameterised by the entity <code>k</code> which is the 53: * byte count of an RSA public shared modulus. 54: * <p> 55: * References: 56: * <ol> 57: * <li><a href="http://www.ietf.org/rfc/rfc3447.txt">Public-Key Cryptography 58: * Standards (PKCS) #1:</a><br> 59: * RSA Cryptography Specifications Version 2.1.<br> 60: * Jakob Jonsson and Burt Kaliski.</li> 61: * </ol> 62: */ 63: public class EME_PKCS1_V1_5 64: { 65: private int k; 66: 67: private ByteArrayOutputStream baos = new ByteArrayOutputStream(); 68: 69: /** Our default source of randomness. */ 70: private PRNG prng = PRNG.getInstance(); 71: 72: private EME_PKCS1_V1_5(final int k) 73: { 74: super(); 75: 76: this.k = k; 77: } 78: 79: public static final EME_PKCS1_V1_5 getInstance(final int k) 80: { 81: if (k < 0) 82: throw new IllegalArgumentException("k must be a positive integer"); 83: 84: return new EME_PKCS1_V1_5(k); 85: } 86: 87: public static final EME_PKCS1_V1_5 getInstance(final RSAKey key) 88: { 89: final int modBits = key.getModulus().bitLength(); 90: final int k = (modBits + 7) / 8; 91: return EME_PKCS1_V1_5.getInstance(k); 92: } 93: 94: /** 95: * Generates an octet string <code>PS</code> of length <code>k - mLen - 96: * 3</code> consisting of pseudo-randomly generated nonzero octets. The length 97: * of <code>PS</code> will be at least eight octets. 98: * <p> 99: * The method then concatenates <code>PS</code>, the message <code>M</code>, 100: * and other padding to form an encoded message <code>EM</code> of length 101: * <code>k</code> octets as: 102: * <pre> 103: * EM = 0x00 || 0x02 || PS || 0x00 || M. 104: * </pre> 105: * <p> 106: * This method uses a default PRNG to obtain the padding bytes. 107: * 108: * @param M the message to encode. 109: * @return the encoded message <code>EM</code>. 110: */ 111: public byte[] encode(final byte[] M) 112: { 113: // a. Generate an octet string PS of length k - mLen - 3 consisting 114: // of pseudo-randomly generated nonzero octets. The length of PS 115: // will be at least eight octets. 116: final byte[] PS = new byte[k - M.length - 3]; 117: // FIXME. This should be configurable, somehow. 118: prng.nextBytes(PS); 119: int i = 0; 120: for (; i < PS.length; i++) 121: { 122: if (PS[i] == 0) 123: PS[i] = 1; 124: } 125: // b. Concatenate PS, the message M, and other padding to form an 126: // encoded message EM of length k octets as 127: // 128: // EM = 0x00 || 0x02 || PS || 0x00 || M. 129: return assembleEM(PS, M); 130: } 131: 132: /** 133: * Similar to {@link #encode(byte[])} method, except that the source of 134: * randomness to use for obtaining the padding bytes (an instance of 135: * {@link IRandom}) is given as a parameter. 136: * 137: * @param M the message to encode. 138: * @param irnd the {@link IRandom} instance to use as a source of randomness. 139: * @return the encoded message <code>EM</code>. 140: */ 141: public byte[] encode(final byte[] M, final IRandom irnd) 142: { 143: final byte[] PS = new byte[k - M.length - 3]; 144: try 145: { 146: irnd.nextBytes(PS, 0, PS.length); 147: int i = 0; 148: outer: while (true) 149: { 150: for (; i < PS.length; i++) 151: { 152: if (PS[i] == 0x00) 153: { 154: System.arraycopy(PS, i + 1, PS, i, PS.length - i - 1); 155: irnd.nextBytes(PS, PS.length - 1, 1); 156: continue outer; 157: } 158: } 159: break; 160: } 161: } 162: catch (IllegalStateException x) 163: { 164: throw new RuntimeException("encode(): " + String.valueOf(x)); 165: } 166: catch (LimitReachedException x) 167: { 168: throw new RuntimeException("encode(): " + String.valueOf(x)); 169: } 170: return assembleEM(PS, M); 171: } 172: 173: /** 174: * Similar to the {@link #encode(byte[], IRandom)} method, except that the 175: * source of randmoness is an instance of {@link Random}. 176: * 177: * @param M the message to encode. 178: * @param rnd the {@link Random} instance to use as a source of randomness. 179: * @return the encoded message <code>EM</code>. 180: */ 181: public byte[] encode(final byte[] M, final Random rnd) 182: { 183: final byte[] PS = new byte[k - M.length - 3]; 184: rnd.nextBytes(PS); 185: int i = 0; 186: outer: while (true) 187: { 188: for (; i < PS.length; i++) 189: { 190: if (PS[i] == 0x00) 191: { 192: System.arraycopy(PS, i + 1, PS, i, PS.length - i - 1); 193: PS[PS.length - 1] = (byte) rnd.nextInt(); 194: continue outer; 195: } 196: } 197: break; 198: } 199: return assembleEM(PS, M); 200: } 201: 202: /** 203: * Separate the encoded message <code>EM</code> into an octet string 204: * <code>PS</code> consisting of nonzero octets and a message <code>M</code> 205: * as: 206: * <pre> 207: * EM = 0x00 || 0x02 || PS || 0x00 || M. 208: * </pre> 209: * <p> 210: * If the first octet of <code>EM</code> does not have hexadecimal value 211: * <code>0x00</code>, if the second octet of <code>EM</code> does not 212: * have hexadecimal value <code>0x02</code>, if there is no octet with 213: * hexadecimal value <code>0x00</code> to separate <code>PS</code> from 214: * <code>M</code>, or if the length of <code>PS</code> is less than 215: * <code>8</code> octets, output "decryption error" and stop. 216: * 217: * @param EM the designated encoded message. 218: * @return the decoded message <code>M</code> framed in the designated 219: * <code>EM</code> value. 220: * @throws IllegalArgumentException if the length of the designated entity 221: * <code>EM</code> is different than <code>k</code> (the length 222: * in bytes of the public shared modulus), or if any of the 223: * conditions described above is detected. 224: */ 225: public byte[] decode(final byte[] EM) 226: { 227: // Separate the encoded message EM into an 228: // octet string PS consisting of nonzero octets and a message M as 229: // 230: // EM = 0x00 || 0x02 || PS || 0x00 || M. 231: // 232: // If the first octet of EM does not have hexadecimal value 0x00, if 233: // the second octet of EM does not have hexadecimal value 0x02, if 234: // there is no octet with hexadecimal value 0x00 to separate PS from 235: // M, or if the length of PS is less than 8 octets, output 236: // "decryption error" and stop. (See the note below.) 237: final int emLen = EM.length; 238: if (emLen != k) 239: throw new IllegalArgumentException("decryption error"); 240: if (EM[0] != 0x00) 241: throw new IllegalArgumentException("decryption error"); 242: if (EM[1] != 0x02) 243: throw new IllegalArgumentException("decryption error"); 244: int i = 2; 245: for (; i < emLen; i++) 246: { 247: if (EM[i] == 0x00) 248: break; 249: } 250: if (i >= emLen || i < 11) 251: throw new IllegalArgumentException("decryption error"); 252: i++; 253: final byte[] result = new byte[emLen - i]; 254: System.arraycopy(EM, i, result, 0, result.length); 255: return result; 256: } 257: 258: private byte[] assembleEM(final byte[] PS, final byte[] M) 259: { 260: // b. Concatenate PS, the message M, and other padding to form an 261: // encoded message EM of length k octets as 262: // 263: // EM = 0x00 || 0x02 || PS || 0x00 || M. 264: baos.reset(); 265: baos.write(0x00); 266: baos.write(0x02); 267: baos.write(PS, 0, PS.length); 268: baos.write(0x00); 269: baos.write(M, 0, M.length); 270: final byte[] result = baos.toByteArray(); 271: baos.reset(); 272: return result; 273: } 274: }