| /* |
| * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code 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 |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package com.sun.crypto.provider; |
| |
| import java.math.BigInteger; |
| import java.util.*; |
| import java.io.*; |
| import sun.security.util.*; |
| import sun.security.x509.*; |
| import java.security.AlgorithmParametersSpi; |
| import java.security.NoSuchAlgorithmException; |
| import java.security.spec.AlgorithmParameterSpec; |
| import java.security.spec.InvalidParameterSpecException; |
| import java.security.spec.MGF1ParameterSpec; |
| import javax.crypto.spec.PSource; |
| import javax.crypto.spec.OAEPParameterSpec; |
| |
| /** |
| * This class implements the OAEP parameters used with the RSA |
| * algorithm in OAEP padding. Here is its ASN.1 definition: |
| * RSAES-OAEP-params ::= SEQUENCE { |
| * hashAlgorithm [0] HashAlgorithm DEFAULT sha1, |
| * maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT mgf1SHA1, |
| * pSourceAlgorithm [2] PSourceAlgorithm DEFAULT pSpecifiedEmpty |
| * } |
| * |
| * @author Valerie Peng |
| * |
| */ |
| |
| public final class OAEPParameters extends AlgorithmParametersSpi { |
| |
| private String mdName; |
| private MGF1ParameterSpec mgfSpec; |
| private byte[] p; |
| private static ObjectIdentifier OID_MGF1; |
| private static ObjectIdentifier OID_PSpecified; |
| |
| static { |
| try { |
| OID_MGF1 = new ObjectIdentifier(new int[] {1,2,840,113549,1,1,8}); |
| } catch (IOException ioe) { |
| // should not happen |
| OID_MGF1 = null; |
| } |
| try { |
| OID_PSpecified = |
| new ObjectIdentifier(new int[] {1,2,840,113549,1,1,9}); |
| } catch (IOException ioe) { |
| // should not happen |
| OID_PSpecified = null; |
| } |
| } |
| |
| public OAEPParameters() { |
| } |
| |
| protected void engineInit(AlgorithmParameterSpec paramSpec) |
| throws InvalidParameterSpecException { |
| if (!(paramSpec instanceof OAEPParameterSpec)) { |
| throw new InvalidParameterSpecException |
| ("Inappropriate parameter specification"); |
| } |
| OAEPParameterSpec spec = (OAEPParameterSpec) paramSpec; |
| mdName = spec.getDigestAlgorithm(); |
| String mgfName = spec.getMGFAlgorithm(); |
| if (!mgfName.equalsIgnoreCase("MGF1")) { |
| throw new InvalidParameterSpecException("Unsupported mgf " + |
| mgfName + "; MGF1 only"); |
| } |
| AlgorithmParameterSpec mgfSpec = spec.getMGFParameters(); |
| if (!(mgfSpec instanceof MGF1ParameterSpec)) { |
| throw new InvalidParameterSpecException("Inappropriate mgf " + |
| "parameters; non-null MGF1ParameterSpec only"); |
| } |
| this.mgfSpec = (MGF1ParameterSpec) mgfSpec; |
| PSource pSrc = spec.getPSource(); |
| if (pSrc.getAlgorithm().equals("PSpecified")) { |
| p = ((PSource.PSpecified) pSrc).getValue(); |
| } else { |
| throw new InvalidParameterSpecException("Unsupported pSource " + |
| pSrc.getAlgorithm() + "; PSpecified only"); |
| } |
| } |
| |
| private static String convertToStandardName(String internalName) { |
| if (internalName.equals("SHA")) { |
| return "SHA-1"; |
| } else if (internalName.equals("SHA256")) { |
| return "SHA-256"; |
| } else if (internalName.equals("SHA384")) { |
| return "SHA-384"; |
| } else if (internalName.equals("SHA512")) { |
| return "SHA-512"; |
| } else { |
| return internalName; |
| } |
| } |
| |
| protected void engineInit(byte[] encoded) |
| throws IOException { |
| DerInputStream der = new DerInputStream(encoded); |
| mdName = "SHA-1"; |
| mgfSpec = MGF1ParameterSpec.SHA1; |
| p = new byte[0]; |
| DerValue[] datum = der.getSequence(3); |
| for (int i=0; i<datum.length; i++) { |
| DerValue data = datum[i]; |
| if (data.isContextSpecific((byte) 0x00)) { |
| // hash algid |
| mdName = convertToStandardName(AlgorithmId.parse |
| (data.data.getDerValue()).getName()); |
| } else if (data.isContextSpecific((byte) 0x01)) { |
| // mgf algid |
| AlgorithmId val = AlgorithmId.parse(data.data.getDerValue()); |
| if (!val.getOID().equals((Object) OID_MGF1)) { |
| throw new IOException("Only MGF1 mgf is supported"); |
| } |
| AlgorithmId params = AlgorithmId.parse(new DerValue(val.getEncodedParams())); |
| String mgfDigestName = convertToStandardName(params.getName()); |
| if (mgfDigestName.equals("SHA-1")) { |
| mgfSpec = MGF1ParameterSpec.SHA1; |
| } else if (mgfDigestName.equals("SHA-256")) { |
| mgfSpec = MGF1ParameterSpec.SHA256; |
| } else if (mgfDigestName.equals("SHA-384")) { |
| mgfSpec = MGF1ParameterSpec.SHA384; |
| } else if (mgfDigestName.equals("SHA-512")) { |
| mgfSpec = MGF1ParameterSpec.SHA512; |
| } else { |
| throw new IOException("Unrecognized message digest algorithm"); |
| } |
| } else if (data.isContextSpecific((byte) 0x02)) { |
| // pSource algid |
| AlgorithmId val = AlgorithmId.parse(data.data.getDerValue()); |
| if (!val.getOID().equals((Object) OID_PSpecified)) { |
| throw new IOException("Wrong OID for pSpecified"); |
| } |
| DerInputStream dis = new DerInputStream(val.getEncodedParams()); |
| p = dis.getOctetString(); |
| if (dis.available() != 0) { |
| throw new IOException("Extra data for pSpecified"); |
| } |
| } else { |
| throw new IOException("Invalid encoded OAEPParameters"); |
| } |
| } |
| } |
| |
| protected void engineInit(byte[] encoded, String decodingMethod) |
| throws IOException { |
| if ((decodingMethod != null) && |
| (!decodingMethod.equalsIgnoreCase("ASN.1"))) { |
| throw new IllegalArgumentException("Only support ASN.1 format"); |
| } |
| engineInit(encoded); |
| } |
| |
| protected AlgorithmParameterSpec engineGetParameterSpec(Class paramSpec) |
| throws InvalidParameterSpecException { |
| if (OAEPParameterSpec.class.isAssignableFrom(paramSpec)) { |
| return new OAEPParameterSpec(mdName, "MGF1", mgfSpec, |
| new PSource.PSpecified(p)); |
| } else { |
| throw new InvalidParameterSpecException |
| ("Inappropriate parameter specification"); |
| } |
| } |
| |
| protected byte[] engineGetEncoded() throws IOException { |
| DerOutputStream tmp = new DerOutputStream(); |
| DerOutputStream tmp2, tmp3; |
| |
| // MD |
| AlgorithmId mdAlgId; |
| try { |
| mdAlgId = AlgorithmId.get(mdName); |
| } catch (NoSuchAlgorithmException nsae) { |
| throw new IOException("AlgorithmId " + mdName + |
| " impl not found"); |
| } |
| tmp2 = new DerOutputStream(); |
| mdAlgId.derEncode(tmp2); |
| tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0), |
| tmp2); |
| |
| // MGF |
| tmp2 = new DerOutputStream(); |
| tmp2.putOID(OID_MGF1); |
| AlgorithmId mgfDigestId; |
| try { |
| mgfDigestId = AlgorithmId.get(mgfSpec.getDigestAlgorithm()); |
| } catch (NoSuchAlgorithmException nase) { |
| throw new IOException("AlgorithmId " + |
| mgfSpec.getDigestAlgorithm() + " impl not found"); |
| } |
| mgfDigestId.encode(tmp2); |
| tmp3 = new DerOutputStream(); |
| tmp3.write(DerValue.tag_Sequence, tmp2); |
| tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)1), |
| tmp3); |
| |
| // PSource |
| tmp2 = new DerOutputStream(); |
| tmp2.putOID(OID_PSpecified); |
| tmp2.putOctetString(p); |
| tmp3 = new DerOutputStream(); |
| tmp3.write(DerValue.tag_Sequence, tmp2); |
| tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)2), |
| tmp3); |
| |
| // Put all together under a SEQUENCE tag |
| DerOutputStream out = new DerOutputStream(); |
| out.write(DerValue.tag_Sequence, tmp); |
| return out.toByteArray(); |
| } |
| |
| protected byte[] engineGetEncoded(String encodingMethod) |
| throws IOException { |
| if ((encodingMethod != null) && |
| (!encodingMethod.equalsIgnoreCase("ASN.1"))) { |
| throw new IllegalArgumentException("Only support ASN.1 format"); |
| } |
| return engineGetEncoded(); |
| } |
| |
| protected String engineToString() { |
| StringBuffer sb = new StringBuffer(); |
| sb.append("MD: " + mdName + "\n"); |
| sb.append("MGF: MGF1" + mgfSpec.getDigestAlgorithm() + "\n"); |
| sb.append("PSource: PSpecified " + |
| (p.length==0? "":Debug.toHexString(new BigInteger(p))) + "\n"); |
| return sb.toString(); |
| } |
| } |