1
0
Fork 0
mirror of https://github.com/pgpainless/pgpainless.git synced 2024-12-22 19:08:00 +01:00

Rename *Alphabet to *Symbol and add javadoc

This commit is contained in:
Paul Schaub 2022-10-27 12:07:22 +02:00
parent b3d61b0494
commit 8ca0cfd3ae
9 changed files with 121 additions and 93 deletions

View file

@ -45,9 +45,9 @@ import org.pgpainless.algorithm.EncryptionPurpose;
import org.pgpainless.algorithm.OpenPgpPacket;
import org.pgpainless.algorithm.StreamEncoding;
import org.pgpainless.algorithm.SymmetricKeyAlgorithm;
import org.pgpainless.decryption_verification.syntax_check.InputAlphabet;
import org.pgpainless.decryption_verification.syntax_check.InputSymbol;
import org.pgpainless.decryption_verification.syntax_check.PDA;
import org.pgpainless.decryption_verification.syntax_check.StackAlphabet;
import org.pgpainless.decryption_verification.syntax_check.StackSymbol;
import org.pgpainless.decryption_verification.cleartext_signatures.ClearsignedMessageUtil;
import org.pgpainless.decryption_verification.cleartext_signatures.MultiPassStrategy;
import org.pgpainless.exception.MalformedOpenPgpMessageException;
@ -334,7 +334,7 @@ public class OpenPgpMessageInputStream extends DecryptionStream {
private void processLiteralData() throws IOException {
LOGGER.debug("Literal Data Packet at depth " + metadata.depth + " encountered");
syntaxVerifier.next(InputAlphabet.LiteralData);
syntaxVerifier.next(InputSymbol.LiteralData);
PGPLiteralData literalData = packetInputStream.readLiteralData();
this.metadata.setChild(new MessageMetadata.LiteralData(
literalData.getFileName(),
@ -344,7 +344,7 @@ public class OpenPgpMessageInputStream extends DecryptionStream {
}
private void processCompressedData() throws IOException, PGPException {
syntaxVerifier.next(InputAlphabet.CompressedData);
syntaxVerifier.next(InputSymbol.CompressedData);
signatures.enterNesting();
PGPCompressedData compressedData = packetInputStream.readCompressedData();
MessageMetadata.CompressedData compressionLayer = new MessageMetadata.CompressedData(
@ -356,7 +356,7 @@ public class OpenPgpMessageInputStream extends DecryptionStream {
}
private void processOnePassSignature() throws PGPException, IOException {
syntaxVerifier.next(InputAlphabet.OnePassSignature);
syntaxVerifier.next(InputSymbol.OnePassSignature);
PGPOnePassSignature onePassSignature = packetInputStream.readOnePassSignature();
LOGGER.debug("One-Pass-Signature Packet by key " + KeyIdUtil.formatKeyId(onePassSignature.getKeyID()) +
" at depth " + metadata.depth + " encountered");
@ -365,8 +365,8 @@ public class OpenPgpMessageInputStream extends DecryptionStream {
private void processSignature() throws PGPException, IOException {
// true if Signature corresponds to OnePassSignature
boolean isSigForOPS = syntaxVerifier.peekStack() == StackAlphabet.ops;
syntaxVerifier.next(InputAlphabet.Signature);
boolean isSigForOPS = syntaxVerifier.peekStack() == StackSymbol.ops;
syntaxVerifier.next(InputSymbol.Signature);
PGPSignature signature;
try {
signature = packetInputStream.readSignature();
@ -391,7 +391,7 @@ public class OpenPgpMessageInputStream extends DecryptionStream {
private boolean processEncryptedData() throws IOException, PGPException {
LOGGER.debug("Symmetrically Encrypted Data Packet at depth " + metadata.depth + " encountered");
syntaxVerifier.next(InputAlphabet.EncryptedData);
syntaxVerifier.next(InputSymbol.EncryptedData);
PGPEncryptedDataList encDataList = packetInputStream.readEncryptedDataList();
// TODO: Replace with !encDataList.isIntegrityProtected()
@ -766,7 +766,7 @@ public class OpenPgpMessageInputStream extends DecryptionStream {
}
if (packetInputStream != null) {
syntaxVerifier.next(InputAlphabet.EndOfSequence);
syntaxVerifier.next(InputSymbol.EndOfSequence);
syntaxVerifier.assertValid();
packetInputStream.close();
}

View file

@ -10,7 +10,7 @@ import org.bouncycastle.openpgp.PGPLiteralData;
import org.bouncycastle.openpgp.PGPOnePassSignatureList;
import org.bouncycastle.openpgp.PGPSignatureList;
public enum InputAlphabet {
public enum InputSymbol {
/**
* A {@link PGPLiteralData} packet.
*/

View file

@ -6,10 +6,20 @@ package org.pgpainless.decryption_verification.syntax_check;
import org.pgpainless.exception.MalformedOpenPgpMessageException;
/**
* This class describes the syntax for OpenPGP messages as specified by rfc4880.
*
* @see <a href="https://www.rfc-editor.org/rfc/rfc4880#section-11.3">
* rfc4880 - §11.3. OpenPGP Messages</a>
* @see <a href="https://blog.jabberhead.tk/2022/09/14/using-pushdown-automata-to-verify-packet-sequences/">
* Blog post about theoretic background and translation of grammar to PDA syntax</a>
* @see <a href="https://blog.jabberhead.tk/2022/10/26/implementing-packet-sequence-validation-using-pushdown-automata/">
* Blog post about practically implementing the PDA for packet syntax validation</a>
*/
public class OpenPgpMessageSyntax implements Syntax {
@Override
public Transition transition(State from, InputAlphabet input, StackAlphabet stackItem)
public Transition transition(State from, InputSymbol input, StackSymbol stackItem)
throws MalformedOpenPgpMessageException {
switch (from) {
case OpenPgpMessage:
@ -27,9 +37,9 @@ public class OpenPgpMessageSyntax implements Syntax {
throw new MalformedOpenPgpMessageException(from, input, stackItem);
}
Transition fromOpenPgpMessage(InputAlphabet input, StackAlphabet stackItem)
Transition fromOpenPgpMessage(InputSymbol input, StackSymbol stackItem)
throws MalformedOpenPgpMessageException {
if (stackItem != StackAlphabet.msg) {
if (stackItem != StackSymbol.msg) {
throw new MalformedOpenPgpMessageException(State.OpenPgpMessage, input, stackItem);
}
@ -38,10 +48,10 @@ public class OpenPgpMessageSyntax implements Syntax {
return new Transition(State.LiteralMessage);
case Signature:
return new Transition(State.OpenPgpMessage, StackAlphabet.msg);
return new Transition(State.OpenPgpMessage, StackSymbol.msg);
case OnePassSignature:
return new Transition(State.OpenPgpMessage, StackAlphabet.ops, StackAlphabet.msg);
return new Transition(State.OpenPgpMessage, StackSymbol.ops, StackSymbol.msg);
case CompressedData:
return new Transition(State.CompressedMessage);
@ -55,17 +65,17 @@ public class OpenPgpMessageSyntax implements Syntax {
}
}
Transition fromLiteralMessage(InputAlphabet input, StackAlphabet stackItem)
Transition fromLiteralMessage(InputSymbol input, StackSymbol stackItem)
throws MalformedOpenPgpMessageException {
switch (input) {
case Signature:
if (stackItem == StackAlphabet.ops) {
if (stackItem == StackSymbol.ops) {
return new Transition(State.LiteralMessage);
}
break;
case EndOfSequence:
if (stackItem == StackAlphabet.terminus) {
if (stackItem == StackSymbol.terminus) {
return new Transition(State.Valid);
}
break;
@ -74,17 +84,17 @@ public class OpenPgpMessageSyntax implements Syntax {
throw new MalformedOpenPgpMessageException(State.LiteralMessage, input, stackItem);
}
Transition fromCompressedMessage(InputAlphabet input, StackAlphabet stackItem)
Transition fromCompressedMessage(InputSymbol input, StackSymbol stackItem)
throws MalformedOpenPgpMessageException {
switch (input) {
case Signature:
if (stackItem == StackAlphabet.ops) {
if (stackItem == StackSymbol.ops) {
return new Transition(State.CompressedMessage);
}
break;
case EndOfSequence:
if (stackItem == StackAlphabet.terminus) {
if (stackItem == StackSymbol.terminus) {
return new Transition(State.Valid);
}
break;
@ -93,17 +103,17 @@ public class OpenPgpMessageSyntax implements Syntax {
throw new MalformedOpenPgpMessageException(State.CompressedMessage, input, stackItem);
}
Transition fromEncryptedMessage(InputAlphabet input, StackAlphabet stackItem)
Transition fromEncryptedMessage(InputSymbol input, StackSymbol stackItem)
throws MalformedOpenPgpMessageException {
switch (input) {
case Signature:
if (stackItem == StackAlphabet.ops) {
if (stackItem == StackSymbol.ops) {
return new Transition(State.EncryptedMessage);
}
break;
case EndOfSequence:
if (stackItem == StackAlphabet.terminus) {
if (stackItem == StackSymbol.terminus) {
return new Transition(State.Valid);
}
break;
@ -112,8 +122,9 @@ public class OpenPgpMessageSyntax implements Syntax {
throw new MalformedOpenPgpMessageException(State.EncryptedMessage, input, stackItem);
}
Transition fromValid(InputAlphabet input, StackAlphabet stackItem)
Transition fromValid(InputSymbol input, StackSymbol stackItem)
throws MalformedOpenPgpMessageException {
// There is no applicable transition rule out of Valid
throw new MalformedOpenPgpMessageException(State.Valid, input, stackItem);
}
}

View file

@ -13,15 +13,15 @@ import java.util.Arrays;
import java.util.List;
import java.util.Stack;
import static org.pgpainless.decryption_verification.syntax_check.StackAlphabet.msg;
import static org.pgpainless.decryption_verification.syntax_check.StackAlphabet.terminus;
import static org.pgpainless.decryption_verification.syntax_check.StackSymbol.msg;
import static org.pgpainless.decryption_verification.syntax_check.StackSymbol.terminus;
public class PDA {
private static final Logger LOGGER = LoggerFactory.getLogger(PDA.class);
private final Stack<StackAlphabet> stack = new Stack<>();
private final List<InputAlphabet> inputs = new ArrayList<>(); // keep track of inputs for debugging / error reporting
private final Stack<StackSymbol> stack = new Stack<>();
private final List<InputSymbol> inputs = new ArrayList<>(); // keep track of inputs for debugging / error reporting
private State state;
private Syntax syntax = new OpenPgpMessageSyntax();
@ -31,12 +31,12 @@ public class PDA {
pushStack(msg);
}
public void next(InputAlphabet input) throws MalformedOpenPgpMessageException {
public void next(InputSymbol input) throws MalformedOpenPgpMessageException {
try {
Transition transition = syntax.transition(state, input, popStack());
inputs.add(input);
state = transition.getNewState();
for (StackAlphabet item : transition.getPushedItems()) {
for (StackSymbol item : transition.getPushedItems()) {
pushStack(item);
}
} catch (MalformedOpenPgpMessageException e) {
@ -56,7 +56,7 @@ public class PDA {
return state;
}
public StackAlphabet peekStack() {
public StackSymbol peekStack() {
if (stack.isEmpty()) {
return null;
}
@ -83,7 +83,7 @@ public class PDA {
*
* @return stack item
*/
private StackAlphabet popStack() {
private StackSymbol popStack() {
if (stack.isEmpty()) {
return null;
}
@ -95,7 +95,7 @@ public class PDA {
*
* @param item item
*/
private void pushStack(StackAlphabet item) {
private void pushStack(StackSymbol item) {
stack.push(item);
}

View file

@ -4,7 +4,7 @@
package org.pgpainless.decryption_verification.syntax_check;
public enum StackAlphabet {
public enum StackSymbol {
/**
* OpenPGP Message.
*/

View file

@ -6,8 +6,25 @@ package org.pgpainless.decryption_verification.syntax_check;
import org.pgpainless.exception.MalformedOpenPgpMessageException;
/**
* This interface can be used to define a custom syntax for the {@link PDA}.
*/
public interface Syntax {
Transition transition(State from, InputAlphabet inputAlphabet, StackAlphabet stackItem)
/**
* Describe a transition rule from {@link State} <pre>from</pre> for {@link InputSymbol} <pre>input</pre>
* with {@link StackSymbol} <pre>stackItem</pre> from the top of the {@link PDA PDAs} stack.
* The resulting {@link Transition} contains the new {@link State}, as well as a list of
* {@link StackSymbol StackSymbols} that get pushed onto the stack by the transition rule.
* If there is no applicable rule, a {@link MalformedOpenPgpMessageException} is thrown, since in this case
* the {@link InputSymbol} must be considered illegal.
*
* @param from current state of the PDA
* @param input input symbol
* @param stackItem item that got popped from the top of the stack
* @return applicable transition rule containing the new state and pushed stack symbols
* @throws MalformedOpenPgpMessageException if there is no applicable transition rule (the input symbol is illegal)
*/
Transition transition(State from, InputSymbol input, StackSymbol stackItem)
throws MalformedOpenPgpMessageException;
}

View file

@ -10,10 +10,10 @@ import java.util.List;
public class Transition {
private final List<StackAlphabet> pushedItems = new ArrayList<>();
private final List<StackSymbol> pushedItems = new ArrayList<>();
private final State newState;
public Transition(State newState, StackAlphabet... pushedItems) {
public Transition(State newState, StackSymbol... pushedItems) {
this.newState = newState;
this.pushedItems.addAll(Arrays.asList(pushedItems));
}
@ -22,7 +22,7 @@ public class Transition {
return newState;
}
public List<StackAlphabet> getPushedItems() {
public List<StackSymbol> getPushedItems() {
return new ArrayList<>(pushedItems);
}
}

View file

@ -4,8 +4,8 @@
package org.pgpainless.exception;
import org.pgpainless.decryption_verification.syntax_check.InputAlphabet;
import org.pgpainless.decryption_verification.syntax_check.StackAlphabet;
import org.pgpainless.decryption_verification.syntax_check.InputSymbol;
import org.pgpainless.decryption_verification.syntax_check.StackSymbol;
import org.pgpainless.decryption_verification.syntax_check.State;
/**
@ -20,7 +20,7 @@ public class MalformedOpenPgpMessageException extends RuntimeException {
super(message);
}
public MalformedOpenPgpMessageException(State state, InputAlphabet input, StackAlphabet stackItem) {
public MalformedOpenPgpMessageException(State state, InputSymbol input, StackSymbol stackItem) {
this("There is no legal transition from state '" + state + "' for input '" + input + "' when '" + stackItem + "' is on top of the stack.");
}

View file

@ -21,8 +21,8 @@ public class PDATest {
@Test
public void testSimpleLiteralMessageIsValid() throws MalformedOpenPgpMessageException {
PDA check = new PDA();
check.next(InputAlphabet.LiteralData);
check.next(InputAlphabet.EndOfSequence);
check.next(InputSymbol.LiteralData);
check.next(InputSymbol.EndOfSequence);
assertTrue(check.isValid());
}
@ -35,10 +35,10 @@ public class PDATest {
@Test
public void testSimpleOpsSignedMesssageIsValid() throws MalformedOpenPgpMessageException {
PDA check = new PDA();
check.next(InputAlphabet.OnePassSignature);
check.next(InputAlphabet.LiteralData);
check.next(InputAlphabet.Signature);
check.next(InputAlphabet.EndOfSequence);
check.next(InputSymbol.OnePassSignature);
check.next(InputSymbol.LiteralData);
check.next(InputSymbol.Signature);
check.next(InputSymbol.EndOfSequence);
assertTrue(check.isValid());
}
@ -52,9 +52,9 @@ public class PDATest {
@Test
public void testSimplePrependSignedMessageIsValid() throws MalformedOpenPgpMessageException {
PDA check = new PDA();
check.next(InputAlphabet.Signature);
check.next(InputAlphabet.LiteralData);
check.next(InputAlphabet.EndOfSequence);
check.next(InputSymbol.Signature);
check.next(InputSymbol.LiteralData);
check.next(InputSymbol.EndOfSequence);
assertTrue(check.isValid());
}
@ -68,11 +68,11 @@ public class PDATest {
@Test
public void testOPSSignedCompressedMessageIsValid() throws MalformedOpenPgpMessageException {
PDA check = new PDA();
check.next(InputAlphabet.OnePassSignature);
check.next(InputAlphabet.CompressedData);
check.next(InputSymbol.OnePassSignature);
check.next(InputSymbol.CompressedData);
// Here would be a nested PDA for the LiteralData packet
check.next(InputAlphabet.Signature);
check.next(InputAlphabet.EndOfSequence);
check.next(InputSymbol.Signature);
check.next(InputSymbol.EndOfSequence);
assertTrue(check.isValid());
}
@ -80,105 +80,105 @@ public class PDATest {
@Test
public void testOPSSignedEncryptedMessageIsValid() {
PDA check = new PDA();
check.next(InputAlphabet.OnePassSignature);
check.next(InputAlphabet.EncryptedData);
check.next(InputAlphabet.Signature);
check.next(InputAlphabet.EndOfSequence);
check.next(InputSymbol.OnePassSignature);
check.next(InputSymbol.EncryptedData);
check.next(InputSymbol.Signature);
check.next(InputSymbol.EndOfSequence);
assertTrue(check.isValid());
}
@Test
public void anyInputAfterEOSIsNotValid() {
PDA check = new PDA();
check.next(InputAlphabet.LiteralData);
check.next(InputAlphabet.EndOfSequence);
check.next(InputSymbol.LiteralData);
check.next(InputSymbol.EndOfSequence);
assertThrows(MalformedOpenPgpMessageException.class,
() -> check.next(InputAlphabet.Signature));
() -> check.next(InputSymbol.Signature));
}
@Test
public void testEncryptedMessageWithAppendedStandalongSigIsNotValid() {
PDA check = new PDA();
check.next(InputAlphabet.EncryptedData);
check.next(InputSymbol.EncryptedData);
assertThrows(MalformedOpenPgpMessageException.class,
() -> check.next(InputAlphabet.Signature));
() -> check.next(InputSymbol.Signature));
}
@Test
public void testOPSSignedEncryptedMessageWithMissingSigIsNotValid() {
PDA check = new PDA();
check.next(InputAlphabet.OnePassSignature);
check.next(InputAlphabet.EncryptedData);
check.next(InputSymbol.OnePassSignature);
check.next(InputSymbol.EncryptedData);
assertThrows(MalformedOpenPgpMessageException.class,
() -> check.next(InputAlphabet.EndOfSequence));
() -> check.next(InputSymbol.EndOfSequence));
}
@Test
public void testTwoLiteralDataIsNotValid() {
PDA check = new PDA();
check.next(InputAlphabet.LiteralData);
check.next(InputSymbol.LiteralData);
assertThrows(MalformedOpenPgpMessageException.class,
() -> check.next(InputAlphabet.LiteralData));
() -> check.next(InputSymbol.LiteralData));
}
@Test
public void testTrailingSigIsNotValid() {
PDA check = new PDA();
check.next(InputAlphabet.LiteralData);
check.next(InputSymbol.LiteralData);
assertThrows(MalformedOpenPgpMessageException.class,
() -> check.next(InputAlphabet.Signature));
() -> check.next(InputSymbol.Signature));
}
@Test
public void testOPSAloneIsNotValid() {
PDA check = new PDA();
check.next(InputAlphabet.OnePassSignature);
check.next(InputSymbol.OnePassSignature);
assertThrows(MalformedOpenPgpMessageException.class,
() -> check.next(InputAlphabet.EndOfSequence));
() -> check.next(InputSymbol.EndOfSequence));
}
@Test
public void testOPSLitWithMissingSigIsNotValid() {
PDA check = new PDA();
check.next(InputAlphabet.OnePassSignature);
check.next(InputAlphabet.LiteralData);
check.next(InputSymbol.OnePassSignature);
check.next(InputSymbol.LiteralData);
assertThrows(MalformedOpenPgpMessageException.class,
() -> check.next(InputAlphabet.EndOfSequence));
() -> check.next(InputSymbol.EndOfSequence));
}
@Test
public void testCompressedMessageWithStandalongAppendedSigIsNotValid() {
PDA check = new PDA();
check.next(InputAlphabet.CompressedData);
check.next(InputSymbol.CompressedData);
assertThrows(MalformedOpenPgpMessageException.class,
() -> check.next(InputAlphabet.Signature));
() -> check.next(InputSymbol.Signature));
}
@Test
public void testOPSCompressedDataWithMissingSigIsNotValid() {
PDA check = new PDA();
check.next(InputAlphabet.OnePassSignature);
check.next(InputAlphabet.CompressedData);
check.next(InputSymbol.OnePassSignature);
check.next(InputSymbol.CompressedData);
assertThrows(MalformedOpenPgpMessageException.class,
() -> check.next(InputAlphabet.EndOfSequence));
() -> check.next(InputSymbol.EndOfSequence));
}
@Test
public void testCompressedMessageFollowedByTrailingLiteralDataIsNotValid() {
PDA check = new PDA();
check.next(InputAlphabet.CompressedData);
check.next(InputSymbol.CompressedData);
assertThrows(MalformedOpenPgpMessageException.class,
() -> check.next(InputAlphabet.LiteralData));
() -> check.next(InputSymbol.LiteralData));
}
@Test
public void testOPSWithPrependedSigIsValid() {
PDA check = new PDA();
check.next(InputAlphabet.Signature);
check.next(InputAlphabet.OnePassSignature);
check.next(InputAlphabet.LiteralData);
check.next(InputAlphabet.Signature);
check.next(InputAlphabet.EndOfSequence);
check.next(InputSymbol.Signature);
check.next(InputSymbol.OnePassSignature);
check.next(InputSymbol.LiteralData);
check.next(InputSymbol.Signature);
check.next(InputSymbol.EndOfSequence);
assertTrue(check.isValid());
}
@ -186,11 +186,11 @@ public class PDATest {
@Test
public void testPrependedSigInsideOPSSignedMessageIsValid() {
PDA check = new PDA();
check.next(InputAlphabet.OnePassSignature);
check.next(InputAlphabet.Signature);
check.next(InputAlphabet.LiteralData);
check.next(InputAlphabet.Signature);
check.next(InputAlphabet.EndOfSequence);
check.next(InputSymbol.OnePassSignature);
check.next(InputSymbol.Signature);
check.next(InputSymbol.LiteralData);
check.next(InputSymbol.Signature);
check.next(InputSymbol.EndOfSequence);
assertTrue(check.isValid());
}