MacContainerReader.java
/*
This file is part of the iText (R) project.
Copyright (c) 1998-2025 Apryse Group NV
Authors: Apryse Software.
This program is offered under a commercial and under the AGPL license.
For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below.
AGPL licensing:
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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 <https://www.gnu.org/licenses/>.
*/
package com.itextpdf.kernel.mac;
import com.itextpdf.bouncycastleconnector.BouncyCastleFactoryCreator;
import com.itextpdf.commons.bouncycastle.IBouncyCastleFactory;
import com.itextpdf.commons.bouncycastle.asn1.IASN1InputStream;
import com.itextpdf.commons.bouncycastle.asn1.IASN1ObjectIdentifier;
import com.itextpdf.commons.bouncycastle.asn1.IASN1OctetString;
import com.itextpdf.commons.bouncycastle.asn1.IASN1Primitive;
import com.itextpdf.commons.bouncycastle.asn1.IASN1Sequence;
import com.itextpdf.commons.bouncycastle.asn1.IASN1Set;
import com.itextpdf.kernel.exceptions.KernelExceptionMessageConstant;
import com.itextpdf.kernel.exceptions.PdfException;
import com.itextpdf.kernel.pdf.PdfDictionary;
import com.itextpdf.kernel.pdf.PdfName;
import java.io.ByteArrayInputStream;
import java.io.IOException;
abstract class MacContainerReader {
private static final IBouncyCastleFactory BC_FACTORY = BouncyCastleFactoryCreator.getFactory();
private final byte[] macContainer;
private final long[] byteRange;
private final byte[] signature;
MacContainerReader(PdfDictionary authDictionary) {
this.macContainer = parseMacContainer(authDictionary);
this.byteRange = parseByteRange(authDictionary);
this.signature = parseSignature(authDictionary);
}
static MacContainerReader getInstance(PdfDictionary authDictionary) {
PdfName macLocation = authDictionary.getAsName(PdfName.MACLocation);
if (PdfName.Standalone.equals(macLocation)) {
return new MacStandaloneContainerReader(authDictionary);
} else if (PdfName.AttachedToSig.equals(macLocation)) {
return new MacSignatureContainerReader(authDictionary);
}
throw new PdfException(KernelExceptionMessageConstant.MAC_LOCATION_NOT_SPECIFIED);
}
abstract byte[] parseSignature(PdfDictionary authDictionary);
abstract long[] parseByteRange(PdfDictionary authDictionary);
abstract byte[] parseMacContainer(PdfDictionary authDictionary);
long[] getByteRange() {
return byteRange;
}
byte[] getSignature() {
return signature;
}
byte[] parseMac() {
IASN1Sequence authDataSequence = getAuthDataSequence();
return BC_FACTORY.createASN1OctetString(authDataSequence.getObjectAt(6)).getOctets();
}
IASN1Set parseAuthAttributes() {
IASN1Sequence authDataSequence = getAuthDataSequence();
return BC_FACTORY.createASN1Set(BC_FACTORY.createASN1TaggedObject(authDataSequence.getObjectAt(5)), false);
}
IASN1Sequence parseMessageDigest() {
IASN1Set authAttributes = parseAuthAttributes();
return BC_FACTORY.createASN1Sequence(authAttributes.getObjectAt(2));
}
byte[] parseMacKey() {
IASN1Sequence authDataSequence = getAuthDataSequence();
IASN1Sequence recInfo = BC_FACTORY.createASN1Sequence(BC_FACTORY.createASN1TaggedObject(
BC_FACTORY.createASN1Set(authDataSequence.getObjectAt(1)).getObjectAt(0)).getObject());
IASN1OctetString encryptedKey = BC_FACTORY.createASN1OctetString(recInfo.getObjectAt(3));
return encryptedKey.getOctets();
}
String parseDigestAlgorithm() {
IASN1Sequence authDataSequence = getAuthDataSequence();
IASN1Primitive digestAlgorithmContainer =
BC_FACTORY.createASN1TaggedObject(authDataSequence.getObjectAt(3)).getObject();
IASN1ObjectIdentifier digestAlgorithm;
if (BC_FACTORY.createASN1ObjectIdentifier(digestAlgorithmContainer) != null) {
digestAlgorithm = BC_FACTORY.createASN1ObjectIdentifier(digestAlgorithmContainer);
} else {
digestAlgorithm = BC_FACTORY.createASN1ObjectIdentifier(
BC_FACTORY.createASN1Sequence(digestAlgorithmContainer).getObjectAt(0));
}
return digestAlgorithm.getId();
}
private IASN1Sequence getAuthDataSequence() {
IASN1Sequence contentInfoSequence;
try (IASN1InputStream din =
BC_FACTORY.createASN1InputStream(new ByteArrayInputStream(macContainer))) {
contentInfoSequence = BC_FACTORY.createASN1Sequence(din.readObject());
} catch (IOException e) {
throw new PdfException(KernelExceptionMessageConstant.CONTAINER_PARSING_EXCEPTION, e);
}
return BC_FACTORY.createASN1Sequence(BC_FACTORY.createASN1TaggedObject(
contentInfoSequence.getObjectAt(1)).getObject());
}
}