All Downloads are FREE. Search and download functionalities are using the official Maven repository.

se.swedenconnect.signservice.signature.signer.crypto.PKCS1V15Padding Maven / Gradle / Ivy

There is a newer version: 1.1.2
Show newest version
/*
 * Copyright 2022 Sweden Connect
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package se.swedenconnect.signservice.signature.signer.crypto;

import java.io.IOException;
import java.util.Arrays;

import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;

import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import se.swedenconnect.security.algorithms.MessageDigestAlgorithm;

/**
 * Provides functions to create and verify RSA Padded data according to PKCS#1 version 1.5
 *
 * 

* Note that PKCS#1 padding includes the digest algorithm as BER encoded * AlgorithmIdentifier. This means that there are multiple ways to encode the same hash * algorithm as 1) BER encoding is not distinguished and 2) the encoding of certain hash * algorithms may differ. One example of this is whether the absent parameters of SHA256 * that MUST be absent, in some cases are implemented as a NULL value resulting in * different encoding *

*

* For this reason, proper validation always require that the decrypted padded data is * inspected and parsed to extract the hash algorithm OID as well asn the encrypted hash * value *

*/ @Slf4j public class PKCS1V15Padding { /** * Prepare the PKCS#1 version 1.5 padding of the hash of the data to be signed. * * @param digestAlgo signature hash algorithm * @param hashValue hash value of the data to be signed * @return padded data to be signed hash * @throws IOException illegal input data */ public static byte[] getRSAPkcs1DigestInfo(@NonNull final MessageDigestAlgorithm digestAlgo, @NonNull final byte[] hashValue) throws IOException { final ASN1EncodableVector digestInfoSeq = new ASN1EncodableVector(); final AlgorithmIdentifier algoId = digestAlgo.getAlgorithmIdentifier(); digestInfoSeq.add(algoId); digestInfoSeq.add(new DEROctetString(hashValue)); return new DERSequence(digestInfoSeq).getEncoded("DER"); } /** * Verifies that message digest value match PKCS#1 padded data * * @param paddedDigest PKCS#1 padded digest value * @param digest the digest value that should be verified against the PKCS#1 padded * digest * @param messageDigestAlgorithm the message digest algorithm that was used to create * the message digest value * @return true on match otherwise false * @throws IOException error in input data */ public static boolean verifyMessageDigest(@NonNull final byte[] paddedDigest, @NonNull final byte[] digest, @NonNull final MessageDigestAlgorithm messageDigestAlgorithm) throws IOException { try (final ASN1InputStream asn1InputStream = new ASN1InputStream(paddedDigest)) { final ASN1Sequence asn1Sequence = ASN1Sequence.getInstance(asn1InputStream.readObject()); final AlgorithmIdentifier hashAlgorithmIdentifier = AlgorithmIdentifier .getInstance(asn1Sequence.getObjectAt(0)); final ASN1ObjectIdentifier paddedDigestAlgoId = hashAlgorithmIdentifier.getAlgorithm(); final ASN1OctetString octetString = ASN1OctetString.getInstance(asn1Sequence.getObjectAt(1)); byte[] paddedDigestValue = octetString.getOctets(); boolean digestMatch = Arrays.equals(paddedDigestValue, digest); boolean hashAlgoMatch = messageDigestAlgorithm.getAlgorithmIdentifier().getAlgorithm() .equals(paddedDigestAlgoId); if (!digestMatch) { log.debug("Digest value does not match padded data"); return false; } if (!hashAlgoMatch) { log.debug("Hash algorithm in padded data does not match specified digest algorithm"); return false; } return true; } catch (final Exception ex) { throw new IOException("Failed to process padding verification data", ex); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy