Java tutorial
/* * * This file is part of the XiPKI project. * Copyright (c) 2014 - 2015 Lijun Liao * Author: Lijun Liao * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License version 3 * as published by the Free Software Foundation with the addition of the * following permission added to Section 15 as permitted in Section 7(a): * FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY * THE AUTHOR LIJUN LIAO. LIJUN LIAO DISCLAIMS THE WARRANTY OF NON INFRINGEMENT * OF THIRD PARTY RIGHTS. * * This program 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * The interactive user interfaces in modified source and object code versions * of this program must display Appropriate Legal Notices, as required under * Section 5 of the GNU Affero General Public License. * * You can be released from the requirements of the license by purchasing * a commercial license. Buying such a license is mandatory as soon as you * develop commercial activities involving the XiPKI software without * disclosing the source code of your own applications. * * For more information, please contact Lijun Liao at this * address: lijun.liao@gmail.com */ package org.xipki.security; import java.io.IOException; import java.math.BigInteger; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.PublicKey; import java.security.interfaces.RSAPrivateCrtKey; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.InvalidKeySpecException; import org.bouncycastle.asn1.ASN1EncodableVector; import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.pkcs.CertificationRequest; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.pkcs.RSASSAPSSparams; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.crypto.AsymmetricBlockCipher; import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.engines.RSABlindedEngine; import org.bouncycastle.crypto.params.RSAKeyParameters; import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; import org.bouncycastle.crypto.signers.PSSSigner; import org.bouncycastle.operator.ContentVerifierProvider; import org.bouncycastle.operator.OperatorCreationException; import org.bouncycastle.operator.bc.BcDefaultDigestProvider; import org.bouncycastle.operator.bc.BcDigestProvider; import org.bouncycastle.pkcs.PKCS10CertificationRequest; import org.bouncycastle.pkcs.PKCSException; import org.xipki.common.util.AlgorithmUtil; import org.xipki.security.api.SignerException; /** * utility class for converting java.security RSA objects into their * org.bouncycastle.crypto counterparts. * * @author Lijun Liao */ public class SignerUtil { static public RSAKeyParameters generateRSAPublicKeyParameter(final RSAPublicKey key) { return new RSAKeyParameters(false, key.getModulus(), key.getPublicExponent()); } static public RSAKeyParameters generateRSAPrivateKeyParameter(final RSAPrivateKey key) { if (key instanceof RSAPrivateCrtKey) { RSAPrivateCrtKey k = (RSAPrivateCrtKey) key; return new RSAPrivateCrtKeyParameters(k.getModulus(), k.getPublicExponent(), k.getPrivateExponent(), k.getPrimeP(), k.getPrimeQ(), k.getPrimeExponentP(), k.getPrimeExponentQ(), k.getCrtCoefficient()); } else { RSAPrivateKey k = key; return new RSAKeyParameters(true, k.getModulus(), k.getPrivateExponent()); } } static public PSSSigner createPSSRSASigner(final AlgorithmIdentifier sigAlgId) throws OperatorCreationException { return createPSSRSASigner(sigAlgId, null); } static public PSSSigner createPSSRSASigner(final AlgorithmIdentifier sigAlgId, AsymmetricBlockCipher cipher) throws OperatorCreationException { if (PKCSObjectIdentifiers.id_RSASSA_PSS.equals(sigAlgId.getAlgorithm()) == false) { throw new OperatorCreationException( "signature algorithm " + sigAlgId.getAlgorithm() + " is not allowed"); } BcDigestProvider digestProvider = BcDefaultDigestProvider.INSTANCE; AlgorithmIdentifier digAlgId; try { digAlgId = AlgorithmUtil.extractDigesetAlgorithmIdentifier(sigAlgId); } catch (NoSuchAlgorithmException e) { throw new OperatorCreationException(e.getMessage(), e); } Digest dig = digestProvider.get(digAlgId); if (cipher == null) { cipher = new RSABlindedEngine(); } RSASSAPSSparams param = RSASSAPSSparams.getInstance(sigAlgId.getParameters()); AlgorithmIdentifier mfgDigAlgId = AlgorithmIdentifier .getInstance(param.getMaskGenAlgorithm().getParameters()); Digest mfgDig = digestProvider.get(mfgDigAlgId); int saltSize = param.getSaltLength().intValue(); int trailerField = param.getTrailerField().intValue(); return new PSSSigner(cipher, dig, mfgDig, saltSize, getTrailer(trailerField)); } static private byte getTrailer(final int trailerField) { if (trailerField == 1) { return org.bouncycastle.crypto.signers.PSSSigner.TRAILER_IMPLICIT; } throw new IllegalArgumentException("unknown trailer field"); } public static boolean verifyPOP(final CertificationRequest p10Request) { PKCS10CertificationRequest p10Req = new PKCS10CertificationRequest(p10Request); return verifyPOP(p10Req); } public static boolean verifyPOP(final PKCS10CertificationRequest p10Request) { try { SubjectPublicKeyInfo pkInfo = p10Request.getSubjectPublicKeyInfo(); PublicKey pk = KeyUtil.generatePublicKey(pkInfo); ContentVerifierProvider cvp = KeyUtil.getContentVerifierProvider(pk); return p10Request.isSignatureValid(cvp); } catch (OperatorCreationException | InvalidKeyException | PKCSException | NoSuchAlgorithmException | InvalidKeySpecException e) { return false; } } public static byte[] pkcs1padding(final byte[] in, final int blockSize) throws SignerException { int inLen = in.length; if (inLen + 3 > blockSize) { throw new SignerException("data too long (maximal " + (blockSize - 3) + " allowed): " + inLen); } byte[] block = new byte[blockSize]; block[0] = 0x00; block[1] = 0x01; // type code 1 for (int i = 2; i != block.length - inLen - 1; i++) { block[i] = (byte) 0xFF; } block[block.length - inLen - 1] = 0x00; // mark the end of the padding System.arraycopy(in, 0, block, block.length - inLen, inLen); return block; } public static byte[] convertPlainDSASigX962(final byte[] signature) throws SignerException { byte[] ba = new byte[signature.length / 2]; ASN1EncodableVector sigder = new ASN1EncodableVector(); System.arraycopy(signature, 0, ba, 0, ba.length); sigder.add(new ASN1Integer(new BigInteger(1, ba))); System.arraycopy(signature, ba.length, ba, 0, ba.length); sigder.add(new ASN1Integer(new BigInteger(1, ba))); DERSequence seq = new DERSequence(sigder); try { return seq.getEncoded(); } catch (IOException e) { throw new SignerException("IOException, message: " + e.getMessage(), e); } } public static byte[] convertX962DSASigToPlain(final byte[] x962Signature, final int keyBitLen) throws SignerException { final int blockSize = (keyBitLen + 7) / 8; ASN1Sequence seq = ASN1Sequence.getInstance(x962Signature); if (seq.size() != 2) { throw new IllegalArgumentException("invalid X962Signature"); } BigInteger r = ASN1Integer.getInstance(seq.getObjectAt(0)).getPositiveValue(); BigInteger s = ASN1Integer.getInstance(seq.getObjectAt(1)).getPositiveValue(); int rBitLen = r.bitLength(); int sBitLen = s.bitLength(); int bitLen = Math.max(rBitLen, sBitLen); if ((bitLen + 7) / 8 > blockSize) { throw new SignerException("signature is too large"); } byte[] plainSignature = new byte[2 * blockSize]; byte[] bytes = r.toByteArray(); int srcOffset = Math.max(0, bytes.length - blockSize); System.arraycopy(bytes, srcOffset, plainSignature, 0, bytes.length - srcOffset); bytes = s.toByteArray(); srcOffset = Math.max(0, bytes.length - blockSize); System.arraycopy(bytes, srcOffset, plainSignature, blockSize, bytes.length - srcOffset); return plainSignature; } }