From 93cf8cc8d9be4128c87cb7cb1b64198e9cbe4013 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Thu, 23 Nov 2023 13:52:02 +0100 Subject: [PATCH 01/40] Remove test with expired key material --- .../KleopatraCompatibilityTest.java | 272 ------------------ 1 file changed, 272 deletions(-) delete mode 100644 pgpainless-core/src/test/java/investigations/KleopatraCompatibilityTest.java diff --git a/pgpainless-core/src/test/java/investigations/KleopatraCompatibilityTest.java b/pgpainless-core/src/test/java/investigations/KleopatraCompatibilityTest.java deleted file mode 100644 index cb6a26b9..00000000 --- a/pgpainless-core/src/test/java/investigations/KleopatraCompatibilityTest.java +++ /dev/null @@ -1,272 +0,0 @@ -// SPDX-FileCopyrightText: 2021 Paul Schaub -// -// SPDX-License-Identifier: Apache-2.0 - -package investigations; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.nio.charset.StandardCharsets; - -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPPublicKeyRing; -import org.bouncycastle.openpgp.PGPSecretKeyRing; -import org.bouncycastle.util.io.Streams; -import org.junit.jupiter.api.Test; -import org.pgpainless.PGPainless; -import org.pgpainless.algorithm.DocumentSignatureType; -import org.pgpainless.algorithm.SymmetricKeyAlgorithm; -import org.pgpainless.decryption_verification.ConsumerOptions; -import org.pgpainless.decryption_verification.DecryptionStream; -import org.pgpainless.decryption_verification.MessageInspector; -import org.pgpainless.encryption_signing.EncryptionOptions; -import org.pgpainless.encryption_signing.EncryptionStream; -import org.pgpainless.encryption_signing.ProducerOptions; -import org.pgpainless.encryption_signing.SigningOptions; -import org.pgpainless.implementation.ImplementationFactory; -import org.pgpainless.implementation.JceImplementationFactory; -import org.pgpainless.key.protection.SecretKeyRingProtector; - -public class KleopatraCompatibilityTest { - - public static final String KLEOPATRA_PUBKEY = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n" + - "\n" + - "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\n" + - "g94JEXpwhb9guKuzYzP/QeBp4qFu5FO87w==\n" + - "=Jz7i\n" + - "-----END PGP PUBLIC KEY BLOCK-----\n"; - public static final String KLEOPATRA_SECKEY = "-----BEGIN PGP PRIVATE KEY BLOCK-----\n" + - "\n" + - "lQVYBGF4StQBDADgAGvvtzCrSa5I9/jIZq0SKxoz7Hz61YM2Hs/hPedXfQeW7lrf\n" + - "qutyXSIb8L964v9u2RGnzteaPwciGSyoMal5teAPOsv6cp7kIDksQH8iJm/9FhoJ\n" + - "hFl2Yx5BX6sBtoXwY63Kf9Vpx/Std9tN34HHI7zrbO70rv6ZcDPFHyWoVdoDZOX1\n" + - "DWbBnOP3SoaNaPnbwEBfEkPwyN/NsnxTfe+IsCYC2byC3NZwYA5FscWFioeJ/UpF\n" + - "HMgZ6utn9mfTexOYEE0mL1mhrc7PbRjDlNasW3GLrpeVN55anT0jvtNXulG4POzG\n" + - "fJ8g3qddcbTXYhQItjurBlkYLV1JOhdCN83IJRect4EIKBkLuEKO0/a7bE6HC7nr\n" + - "PLw9MWGgcnDe2cTc4a6nAGC/eMeCONQlyAvOIEIXibbz4OB0dTNA5YYTMBHVO7n0\n" + - "GbNg8eqw+N+IijboLtJly+LshP81IdQMHg0h6K3+bfYV0rwC/XmR387s+pVpAp5k\n" + - "Lrw8Rt+BsQSY2O8AEQEAAQAL/jBENv3Iud52umyzrfI0mZ9cFUHR994uqp67RezR\n" + - "Y2tpH/0IMCGY2THj2oktt3y5s/OFJ3ZCrhdo9FcHGKXHSa7Vn0l40GIPV6htPxSH\n" + - "cz1/Dct5ezPIxmQpmGfavuTYGQVC3TxQjkJEWTcVp/YgLn0j+L2708N6f5a9ZBJa\n" + - "E0mx8g+gKqLCd/1JGp/6+YI39/q/cr9plqUoC31ts7dj3/zSg+ZCV4nVHwnI0Np4\n" + - "o0iSoID9yIaa3I0lHwNgR1/82UVEla94QGKSRQqjTrgsTLPFIACNtSI/5iaPdKZK\n" + - "a01oic1LKGEpuqpHAbnPnCAKrtWODk8B/3U4CABflXufI3GTYOZeaGZvd6I/lx/t\n" + - "HQcg5SKE8vNIB1YZ2+rSsznAFmexaLjPVG3XhGQdBVoV/mmlcI71TUEcL9kXYMh6\n" + - "JnwH5/F2kG9JAXC+0Y3R9Ji+wabVGMUHxugcXpQa0d/malCZaS/dviDUfZ1KbDjH\n" + - "Jlzew7cmfRtiw4tfczboekeSbQYA6bh6IFqQlcW7qj34TAg8h8t34Q2o2U0VMj96\n" + - "OiG8B/LARF89ue4CaQQMQt16BHeMhePBAhPCkkCEtmbXremHsrtn6C149cS9GAEt\n" + - "fSAHVGedVDHzke/K84uHzBbY0dS6O6u2ApvWOutgWpB5Le4A7WTslyAdLWRZ1l69\n" + - "H2706M9fgGClVsQByCNVksDEbOizIlAkFOq0b39u8dnb063A9ReAuk/argCA7JHU\n" + - "j3BFIF5crIn+YrWl6slFuoXGWTXlBgD1WsVhU4hXJ5g35TOso0rEND/wHrjW0W4F\n" + - "LViA5yAt9sVLNGgm9Ye3YSVIHId6HiJQZmsWJb81WD5dvBLl74icZmfSWtRTwvCZ\n" + - "0k3rYlu3Ex4bQUwoyhSlDoPJ9YMaumd1yaM3nMeyrlaHYIpV8NtqSuqJc7i2iNX1\n" + - "3s9AotipHYEUOlsp936bNEuh0m8xXEZ2C8qjpNenymg8XfNd/IH2M4Sjzz+pN5sS\n" + - "gQt+pQhYFnW0Gersb/X3OsAtLtRE5kMF/3v7GAz7usMcajqbh9qB+Ytp4n1u3aQC\n" + - "ck1exVOwdLDZgsHfojO1SEFd3IafO01xp+TmS8qIoZvKJegM+qq9px1PHSTRnb4D\n" + - "8tuBxtdoUE7n+g3Li74je7+DEdcq6g9ZjgyeosCHGItUwTcCMqnHa+ikjQjsnnzu\n" + - "eSwvVSfMJQYyZrZ5qYgQZKcovkFDvgXiC/jqfDd6GeAfbxzL2cyAYWvUdGln79O3\n" + - "Tc7ZWd0Xn6IaMPVPRBvH4RsaWqFdO0pIOuH7tCFLbGVvcGF0cmEgPGtsZW9wYXRy\n" + - "YUB0ZXN0LmRvbWFpbj6JAdQEEwEKAD4WIQTNjMcS6UvITk+RpSnoRWAoqhM/WQUC\n" + - "YXhK1AIbAwUJA8HtzAULCQgHAwUVCgkICwUWAgMBAAIeAQIXgAAKCRDoRWAoqhM/\n" + - "WcKXC/97E6uTcfRoo6rAHqAy0D1s4mBgbgube/0Qzf2YZJxMmABpkyUkhUxnuoFQ\n" + - "IRvD2U4kxkuC5WZUk3yxVgTrM108bGZAstyJcOF4Yh2ZAOL8rWPa6MpZRVkS9qyK\n" + - "7uk7YZyXcqOpp652m8q0QM9Qe2SrNNAeDGlClKTLnzC5svKhf9s2cKTLcz+27vvi\n" + - "QnYcYdPLpLhzUod/qThf3q8/VXvKgqn526RgtfC2bvckCLudf/A6ahAjgjrR+zbp\n" + - "kUOmgSQBlWNm2Pqp9P26dL5dl6SVzSyJpnnBm9W5IZZwji/j+sD9lT0qMOuJq0S7\n" + - "RnMT9eWXUwdDKHgHfXOPA/wuYtKs0cwuZP7ucz6cJ8KijvW5kaS65HSwprptOgFQ\n" + - "6WzWiVGYppl/01ImNbQrTEvdMTN24zuH6gM0t/ltJJkWgMbCwdFboTneXtkN7u04\n" + - "f5kZIO4JshW7h1DqTQ1UwUj6DFPBBT/hFLeF5G+fvf0/tVEvJSXiBfT+rwRqcc9B\n" + - "f01ci5KdBVgEYXhK1AEMAMx67IMc/ien9md9odcoufPoL7qWsX8HQuEZcPG835wK\n" + - "kW/JuaoZnvgM6QpVdWWZeO9vbanr6g4PXrf8o6p+uMpP+h5WEyCUxzato3Ln5dYd\n" + - "yMoGGmvFtf1siGtASOa8/nukh9DzezV2BCxaXEjBfWDzpfTi7q2cb5/A10auFnBx\n" + - "tqK8lPkXza4ooiqC0NupxS2o5CmD7NQ7at1uCNbDktk8GIL90eRbJ0a/NaucCAOZ\n" + - "UCwmK1rYX4/HCaeLenmpTaEEmYm5WjXnDp6VJPVK+feOKbmCptdeGHYHANIM8SnS\n" + - "5FmVXqv1EyUf6Ozgi8qK94bN1dPOZs+XxT7gcfKc8zVNZHEJpc0XjDgGWeWrOCDS\n" + - "MVdXNXS1eTUclNw/guaajTGl/k4SxsJm/rWoMk7bRAwfD1j2pT+VwKxe+a0V8QNN\n" + - "lJ+8gQCWmju28ifcf3gSJVzkU2lF9aueDA+fC3ebdCSYbeWR3lafG7KMf8tsoy24\n" + - "EL/dC4o2uvJK9cUvhIvnVwARAQABAAv9ExmcWWGY6p1e1StACyKrvqO+lEBFPidb\n" + - "Jj7udODT8PXFFgW9c60cU0aUHLn/fZ5d/zI6XSKYj02nkaoQo6QIoM/i/iMY0En1\n" + - "aHRvDb7+51w1iDa/uwy8biVNgi8pYBw2l9gLiQdlR94ej6y1GBAIJR6ShD26VmSE\n" + - "F2O3osuEybtleEKt660/MiMWMBWzaqwAq2jY6c5/4xHVw+87oMv4k0AbeLOQKojK\n" + - "h2o5mi5jSpVvOWCAsOYAhHlEEUQPDFQ1rbJ3P3XcRZE4EIxP2eKDyfyOXRTihLDl\n" + - "/9hqOf57wo0C43bnc1BkD6sk+ptKgUifpUHHejg/i7HINFivh7jCgCtoskf2P9BL\n" + - "WFuaPZVLQSVE5X2PsgeIYK9/eGeNxfXgtwRyUd8DtBge11tsMaENUTm39p36my2K\n" + - "jBgoEdBIQo1Mpi1EZba+L6pyw9bPFnj5H+opSe+X9/spkS9DyPOPGY7rCSTgv+7q\n" + - "Ph2WbtRRJslitLEjT9tNgwMRGWsgdbcpBgDgzujDUQb1coCdgw1gsQSTPir9hJxF\n" + - "Q+2DAbGpkqiYayHJqH7T9wGhiY8QoqLIejNawkrel4yTtYmM7pgtURWrkzz/jHAT\n" + - "3NNRTyvFqMmjwOIoV83tW8247uA8eofc981wEVayJ4y/KDcvU04FBrjCEoOUQMXw\n" + - "Ychr4cGiEckGBxAib6fVxjsU3PUIuUDpm9NC53Rc0GmwlduiZSJqRZQRgytLxWdM\n" + - "Va4c5oHdc0qpjCgk5qkW/09lI5kxTlMk3E0GAOjZ+HSQV8rI7qu7G0Qno9MP0Q49\n" + - "Qo5Hf4uV+I/6Iim/Eq5LWKmmairIob47jLtmhoIo7LArTm+9NsThFidc6wjRYgtT\n" + - "kGx4KUTEl8d0/mHV8GBzNNyRM7UOoLVjgf4tljFa8d2hQNMXZyBsIkLyoL6cL2sx\n" + - "aMZWl9jjh0bYE4TiTDIO1cfddxGjCPG9i12Z+yMl5p0g+r+IUAbuSh4+Yo7PUIKF\n" + - "8v+mqZRC9M9C/T/qOAB2gL2vDEZ4TdLAZfYUMwX9E/I1e0gHPlqXmQ/znTkjuCXd\n" + - "JopVXmvvku8SvVFb4pcW1k5Tk3iEj7nilQ64I5bONFUot+qKTtxAM2Fwxo0EjFZD\n" + - "TCP5RbY60iJcnhpk5mDGD41O1xe2HBkJw8dC5xUr1pPs+7Y8gMXN3qK4JcrLfLSO\n" + - "pOb623ir9jtJWLjv1wOvr7KsWZxg8XOQq8+AkEprUjb8v8WsJY5c7L8vSJ5OYlOP\n" + - "gv9Tj3MVmV1jGhH9pR+zGcclyathY3Ytloy1zZxR3WCJAbwEGAEKACYWIQTNjMcS\n" + - "6UvITk+RpSnoRWAoqhM/WQUCYXhK1AIbDAUJA8HtzAAKCRDoRWAoqhM/WZIbC/4r\n" + - "XsWOfqpFo4xnfHCwLayU84UEZZOrO7e3gRUrk8sJSgtX9cFabuXYzh0zx/B9CVjA\n" + - "AMbR0JbpNyHEK7gTBaGqN8Zmvth1tceAtAH6y+AtNM8VFMarZn2YvNTVNIs5hTQA\n" + - "XXBBxmxPIzfOsCGogJ0tXputRfr47jEzCyVauekkCYVkspn+M+HfIFSMu1s3krh5\n" + - "x3A2zHAnxczdZJ9k/5OYGr+MBHM95y4s1GLE/qxSos4Fc0gy5UhXCUD3fmvCsG6P\n" + - "4Z8w7fc4JlYq81NP9koHdHeiGraZZGD81powE3t4bZiqxlw+Ef6xe2hJzwpEfJPF\n" + - "jCz5XrnpwkRkIuSiszbnr2NlPAODIijbeRDPFnanFw9z7+57FYuHTXPCCtU2eAXz\n" + - "d2ARUC/oTvxZO2qYqmQ7t7DaRuyUdFd+5bRwCtBxXc58j+/aIsZJ1eqX3QFWyMs0\n" + - "F5Pxap6b24wmOL/w1i8+muJ/LWED4YPeCRF6cIW/YLirs2Mz/0HgaeKhbuRTvO8=\n" + - "=cgLL\n" + - "-----END PGP PRIVATE KEY BLOCK-----\n"; - // signed and encrypted - public static final String KLEOPATRA_MESSAGE = "-----BEGIN PGP MESSAGE-----\n" + - "\n" + - "hQGMA2gglaIyvWSdAQv+NjugJ3Sqk7F9PnVOphT8TNc1i1rHlU9bDDeyZ2Czl6KA\n" + - "YXwSP5KmwgTJH+vt9N5xrbKOGCuSCJNeb0wzH/YpQHLL5Hx5Pk0KtNH8BCevApkM\n" + - "Rcn4EKiXMmTFyib0fCPlqvEvqdD1ni1IliHNLxR/TYCSxbmu3TqPie70PiLsB32l\n" + - "6QKDi1U3HftsZOLLgIPbd1IqnSMeT3E15oD8LTQe3k/CV+huA54wrIeqDxfJpcAu\n" + - "rvb4rLVvGmaF67FXekMEDjD3cdk2m6WJ8c1myh3EUpDRlMPobhgeEV+h28heGuhu\n" + - "g2Id97DMfUhxypGbQ/rlwHE3UMvdW3YS0KRT7UfPee0F2m737b/aWO341LOzJz94\n" + - "xggPafIC6IseQQVZirocG1CLl0lauWZoXbfmzrXCT+YGNuaNjlE01BYPBjgEygle\n" + - "7Kur60YkB0H6fACskcudWDRFTsjEgIZa3riHou7XmvqupvJC+hyYdH3QqyFMvdix\n" + - "03/E9ePUs051Bvzn+a/dhQGMAwAAAAAAAAAAAQv/RtljqQ2BsB0KkdzZtnfY+CZZ\n" + - "PBYvloxplK+Bs8aoLVujyI7g6weOvFD49tSowsvJ//DleDpcKe4UZA/WRj5HlB1J\n" + - "5zLK5qlWb8El6QKlwEKB02zHDv244Bm9ZROnSK3CrEqRcfdBQIx4ThEOZlG0cE60\n" + - "iTbrda2SYUDpHh4Re/qhw/wvc0uUf+59u8WU5AIpgfLBU2fNEjOr6LMIsR3Edvf8\n" + - "zIFUrHlfvKQaAnZYU79dA0ZnTYgLiwMWB19nvhnSIdWAC3tJUsiuEIzEzA+vVbG/\n" + - "YrTOMR+vFm+dVOcVanzn0vnV0n8+np1kM1V2JgGRKV6XybS1oUbNPvpv79FBgfPi\n" + - "F3WghBHZf9lTaj4w7LtQSojvC0YxSoxfTif/MMxNZUoexQbk0jE97ibeFk6rqrBn\n" + - "46G2WbrrReDyOUekSkM5MQ/bZ1GJuFfC+kGyHETBejsfn0ZKa2RUla9k3vYFcDJC\n" + - "Et7Vwv81SF4yzvSwiV0rFx1RcyZaGlJumjCkqaHHhQIMAwAAAAAAAAAAAQ/+KTsY\n" + - "vnPMOmjmLqu7BQwx3jUaEmCXTurv5XHMbAEcq0UAwHJ/XAcJe7B1707Fu1sSJJjV\n" + - "3rJVHGUv7+APg5/vALx/FGlKk/12M8NhgOreLCLa/vQ9NmNrcfqGQdZtpk6OQxLv\n" + - "DcnCbUjyTO2IFRjmzEy8d8rne/FMC1MZD9hY1IboJWk5fN1NCsIIbPn3OSqVIaa1\n" + - "9fJj6D7SGacraBNJwl0x22ipV4yLtpo2DtnPJGK4xgTm0eW7eUK3nIfC/foHEgxG\n" + - "Bny1axnKqC9TFhAQ7Eo+Wh9eAiXtFBY7po7tfYmhb6mHBMAfYsVvCCyLNqUbXiV9\n" + - "kXWMBf0yxtNQlkx1jK+iqfGBm3EfHKncXGfl6zxwkh1FZXcY2EyCavkGND+3Gexg\n" + - "vbCUltulq1Fv1WjOGz9Icc5pK9AyjUuc/AQ4k7WhCVhCmbpsb/Cq6LsiqOC219dE\n" + - "r5TLGr+K1289PVOgbd06BL5NVP6qeO5fyWUA/Bs+exxqEDKce0f0ppKkcGNAv9p/\n" + - "Lg57FxT8aYVBgSoTv1DASquZANrO3kp7M3nC5lVzUldz8aS4YEirLLTF0MBnZEZ8\n" + - "MRcG8h8oSKozw+cuJXNF+bFiKM0wwRyw0AXGt69/lrPlWKMCfuK3n8vqxVPJ78JD\n" + - "ut8xHNWelqS2uO0qinvfbBcKzptYUm8ctNbHlSLS6QEnmjoiF/jobEDWsp6yBaym\n" + - "o7h9VQrmCKjKsoQzoF5KYHW87BLb2YRnx5WwTvN1BvZTNqNjkm9tuDTIwhTUx/L/\n" + - "B8l+KqpGcrmsldQ/pF/W3m2mFlsqpb02uWJSpXQ7NEavjvPThKPJHUnni4YtCg5b\n" + - "v8Zy/zvYgGj5y4DDjM84Xw/HcMdyHsWIcGosZ6W/jJhO7sECXqS6HoF5zFsIBPX9\n" + - "dEM4GS5TapLe0s7DyC0bK7VbPgLMBxPmbBSVp3O72qKpvgc6PAggTJHNhd6MLsJA\n" + - "JAiAOF/KNNZxSdMWIXqMyMviSPeU9+KclOG7iiR75Q5kIbpj9hWo5ullxr6XrHl2\n" + - "HFR+5jnmbSNwz/cf0vwkTnNG/Crofyy0kPTfGp5Ku4hp0wIhWXM9f8m7tuoxI3ep\n" + - "uNwB7FOs3xemsxAmoufyWcsyxnVf/3OJLWejIcIK1v3NmoiSxFQXl2cmiRVLTtAT\n" + - "oNjUT9QDQiyi8YR+CepV6RnBSmRomr7HfRAoACaCg6ToaXm0Dc8OQSge2X80ifdD\n" + - "NUcfhQAivaVAqhAogUIaPp9yqwTWaZ00N5cPH4HItPJtukb+Fsove2SoF+iPQre6\n" + - "hDjZCNyfUjT+wnca315nN+9D6Z1JgV5YEM23sFKp4M732Zdb5JlR0DXfDEuQH1NL\n" + - "hXOcpr9LpAvASH7weiVTEYxNz5KzFkUQA5YKLLeDwtcK\n" + - "=MgH4\n" + - "-----END PGP MESSAGE-----\n"; - public static final String PGPAINLESS_MESSAGE = "-----BEGIN PGP MESSAGE-----\n" + - "Version: PGPainless\n" + - "\n" + - "hQGMA2gglaIyvWSdAQv/Y9Wx763qAM95+teCUPPNRc5Iwqbc5uFjxfbcwsHIWdiZ\n" + - "n2wHNUmd2dUqYgpqOcBwZ/fUJuoHj/uXKZ1pbz2QSVYaL9MulKpgWiVAo0K2w0Oc\n" + - "97KfZ0d66tcZIhslVpZW06+lXuwMyjjjExe32fAkPFnYyTNORljyYlb/RDSkh7Ke\n" + - "Q+48fLR2kitV0WyRZ+d9cMfx2+D2gWYiaFGek9SrhI8L+nNd4UKvM4K4sSq4JHYf\n" + - "DCxGPWYOaTculuX8dfDh3ftHbrmL2Ca7Iv4NB0kSduG8Gin2OWyeSIPIwpF2ci9g\n" + - "cIBssAYhmS88FQit5pW9z2RZ/e9XmYIP++kz3/EdI6DqkiPUv1fiHTrJBC93LvVg\n" + - "pq75h9RNFuUlqR09SVuB/uZB6tYgv77vy5lPFo+wmLjM41aS4+qI1hBI3Ym4XTc1\n" + - "spPA0sEHtQTQ/xRNYqGpwunJniMF3ukWpOB6UNvQld+p2lj8czexhEAcne1cjey/\n" + - "f0/WUnluSt0HIg8Mnd7s0ukBhb4YxjvARjuqi6PikGz4JPshRwB8dPtS9FQiRxL7\n" + - "obaPHXlmLwohEtT3akzoIj/9C3Y7qnfreSllDgRDxRVFPXy5QnQqpsTy2JuJ4cvo\n" + - "p55RE2kyJ3vBZlB6T53pSgC00hQnNxoqgy7aejRItlec7zx5DnEg8t4rA7LYEGLT\n" + - "MBLWbTRc/njH6GTyc/3x7j9k8V83exqpF6fXrE3GP1C3fBxHY2S9/5BFAlzimplz\n" + - "Mow4S15D04EllRRk6f9HKY598xS4QlDEW/f3utwkQ8+/lNqesVuV8n76WDldMv2O\n" + - "5gTqAZ/pKhDKRLY6km4B2+2IAt2zg+V141wryHJgE/4VyUbu7zZxDIcDouuATQvt\n" + - "wNMnntqy3NTbM7DefSiYe9IUsTUz/g0VQJikoJx+rdX6YzQnRk/cmwvELnskQjSk\n" + - "aGd92A4ousaM299IOkbpLvFaJdrs7cLH0rEQTG5S3tRJSLEnjr94BUVtpIhQDo3i\n" + - "455UahKcCx/KhyIzo+8OdH0TYZf5ZFGLdTrqgi0ybAHcLrXkM+g2JOsst99CeRUq\n" + - "f/T4oFvuDSlLU56iWlLVE7gvDBibXfWIJ65YBHY4ueEzBC/3xOVj+dmTM2JfUSX7\n" + - "mqD25NaDCOuN4WhJmZHC1wyipj3KYT2bLg4gasHr/LvEI+Df/DREdXtrYAqPqZYU\n" + - "0QuubMF4n3hMqmu2wA==\n" + - "=fMRM\n" + - "-----END PGP MESSAGE-----"; - - @Test - public void testMessageDecryptionAndVerification() throws PGPException, IOException { - ImplementationFactory.setFactoryImplementation(new JceImplementationFactory()); - PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(KLEOPATRA_SECKEY); - PGPPublicKeyRing publicKeys = PGPainless.readKeyRing().publicKeyRing(KLEOPATRA_PUBKEY); - - ConsumerOptions options = new ConsumerOptions() - .addDecryptionKey(secretKeys) - .addVerificationCert(publicKeys); - - ByteArrayOutputStream out = new ByteArrayOutputStream(); - DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify() - .onInputStream(new ByteArrayInputStream(KLEOPATRA_MESSAGE.getBytes(StandardCharsets.UTF_8))) - .withOptions(options); - - Streams.pipeAll(decryptionStream, out); - decryptionStream.close(); - } - - @Test - public void testEncryptAndSignMessage() throws PGPException, IOException { - PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(KLEOPATRA_SECKEY); - PGPPublicKeyRing publicKeys = PGPainless.readKeyRing().publicKeyRing(KLEOPATRA_PUBKEY); - - ProducerOptions options = ProducerOptions.signAndEncrypt( - EncryptionOptions.encryptCommunications() - .addRecipient(publicKeys) - .overrideEncryptionAlgorithm(SymmetricKeyAlgorithm.AES_128), - SigningOptions.get() - .addInlineSignature(SecretKeyRingProtector.unprotectedKeys(), secretKeys, DocumentSignatureType.BINARY_DOCUMENT) - ); - - ByteArrayOutputStream out = new ByteArrayOutputStream(); - EncryptionStream encryptionStream = PGPainless.encryptAndOrSign() - .onOutputStream(out) - .withOptions(options); - - ByteArrayInputStream in = new ByteArrayInputStream("Hallo, Welt!\n\n".getBytes(StandardCharsets.UTF_8)); - Streams.pipeAll(in, encryptionStream); - encryptionStream.close(); - } - - @Test - public void testMessageInspection() throws PGPException, IOException { - MessageInspector.EncryptionInfo info = MessageInspector.determineEncryptionInfoForMessage( - new ByteArrayInputStream(KLEOPATRA_MESSAGE.getBytes(StandardCharsets.UTF_8))); - } -} From e32d6ac34c168125891ced9cecd811ebe14da69f Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Thu, 23 Nov 2023 13:54:23 +0100 Subject: [PATCH 02/40] Bump sop-java to 7.0.1 --- version.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.gradle b/version.gradle index 73c5547c..f06cdd0d 100644 --- a/version.gradle +++ b/version.gradle @@ -14,6 +14,6 @@ allprojects { logbackVersion = '1.2.11' mockitoVersion = '4.5.1' slf4jVersion = '1.7.36' - sopJavaVersion = '7.0.0' + sopJavaVersion = '7.0.1' } } From d09b646011be63ddf1b5e3971015426fdddf4137 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Thu, 23 Nov 2023 13:55:04 +0100 Subject: [PATCH 03/40] PGPainless 1.6.3 --- README.md | 2 +- pgpainless-sop/README.md | 4 ++-- version.gradle | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 659ca896..7f193370 100644 --- a/README.md +++ b/README.md @@ -191,7 +191,7 @@ repositories { } dependencies { - implementation 'org.pgpainless:pgpainless-core:1.6.2' + implementation 'org.pgpainless:pgpainless-core:1.6.3' } ``` diff --git a/pgpainless-sop/README.md b/pgpainless-sop/README.md index 55cf0cb2..12bdaec5 100644 --- a/pgpainless-sop/README.md +++ b/pgpainless-sop/README.md @@ -23,7 +23,7 @@ To start using pgpainless-sop in your code, include the following lines in your ... dependencies { ... - implementation "org.pgpainless:pgpainless-sop:1.6.2" + implementation "org.pgpainless:pgpainless-sop:1.6.3" ... } @@ -34,7 +34,7 @@ dependencies { org.pgpainless pgpainless-sop - 1.6.2 + 1.6.3 ... diff --git a/version.gradle b/version.gradle index f06cdd0d..487da535 100644 --- a/version.gradle +++ b/version.gradle @@ -5,7 +5,7 @@ allprojects { ext { shortVersion = '1.6.3' - isSnapshot = true + isSnapshot = false pgpainlessMinAndroidSdk = 10 javaSourceCompatibility = 1.8 bouncyCastleVersion = '1.76' From d812a2a8b6637cb7eb997209b4450ea0d316680f Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Thu, 23 Nov 2023 13:56:56 +0100 Subject: [PATCH 04/40] PGPainless 1.6.4-SNAPSHOT --- version.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version.gradle b/version.gradle index 487da535..ad7e1c18 100644 --- a/version.gradle +++ b/version.gradle @@ -4,8 +4,8 @@ allprojects { ext { - shortVersion = '1.6.3' - isSnapshot = false + shortVersion = '1.6.4' + isSnapshot = true pgpainlessMinAndroidSdk = 10 javaSourceCompatibility = 1.8 bouncyCastleVersion = '1.76' From ab74e157d0a64bf190e9a9708615595a1ccaf626 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Thu, 23 Nov 2023 13:58:40 +0100 Subject: [PATCH 05/40] Update CHANGELOG --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f86b67f..142d8fb5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ SPDX-License-Identifier: CC0-1.0 # PGPainless Changelog +## 1.6.3 +- Bump `sop-java` to `7.0.1` +- `decrypt --verify-with`: Fix to not throw `NoSignature` exception (exit code 3) if `VERIFICATIONS` is empty + # 1.6.2 - Switch `bcpg` and `bcprov` artifacts from `-jdk15to18`variant to `-jdk18on` - Bump `bcpg-jdk8on` to `1.76` From 0c5521f82a7e1612dc301a4e9007999fc4c52c92 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Thu, 23 Nov 2023 14:01:13 +0100 Subject: [PATCH 06/40] Fix changelog version headers --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 142d8fb5..d726fc2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ SPDX-License-Identifier: CC0-1.0 - Bump `sop-java` to `7.0.1` - `decrypt --verify-with`: Fix to not throw `NoSignature` exception (exit code 3) if `VERIFICATIONS` is empty -# 1.6.2 +## 1.6.2 - Switch `bcpg` and `bcprov` artifacts from `-jdk15to18`variant to `-jdk18on` - Bump `bcpg-jdk8on` to `1.76` - Bump `bcprov-jdk18on` to `1.76` @@ -17,7 +17,7 @@ SPDX-License-Identifier: CC0-1.0 encrypting to legacy keys which do not carry any key flags. - Allow overriding of reference time in `EncryptionOptions` and `SigningOptions`. -# 1.6.1 +## 1.6.1 - `KeyRingBuilder`: Require UTF8 when adding user-ID via `addUserId(byte[])` - `pgpainless-sop`: Remove dependency on jetbrains annotations - Add `CertificateAuthority` interface to allow integration with [`pgpainless-wot`](https://github.com/pgpainless/pgpainless-wot) From 4b474b468326dea7380fe0a25393bd037346ffa4 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Thu, 30 Nov 2023 19:55:06 +0100 Subject: [PATCH 07/40] Backport b0caa95378d4ce3b75f18df784b6c48bf5350c71 Properly feed an EOS token to the push down automata in OpenPgpMessageInputStream.read() --- .../decryption_verification/OpenPgpMessageInputStream.java | 1 + 1 file changed, 1 insertion(+) diff --git a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/OpenPgpMessageInputStream.java b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/OpenPgpMessageInputStream.java index b9ead7e7..dd8cf0e2 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/OpenPgpMessageInputStream.java +++ b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/OpenPgpMessageInputStream.java @@ -712,6 +712,7 @@ public class OpenPgpMessageInputStream extends DecryptionStream { public int read() throws IOException { if (nestedInputStream == null) { if (packetInputStream != null) { + syntaxVerifier.next(InputSymbol.EndOfSequence); syntaxVerifier.assertValid(); } return -1; From c61a129e082363b809a43b089de2a35ed81c39f0 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sun, 26 Nov 2023 10:55:47 +0100 Subject: [PATCH 08/40] add unit test to read decryption stream beyond end --- .../DecryptAndVerifyMessageTest.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/DecryptAndVerifyMessageTest.java b/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/DecryptAndVerifyMessageTest.java index e939de0a..69a6a2e2 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/DecryptAndVerifyMessageTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/DecryptAndVerifyMessageTest.java @@ -83,6 +83,24 @@ public class DecryptAndVerifyMessageTest { assertEquals(new SubkeyIdentifier(TestKeys.JULIET_FINGERPRINT), metadata.getDecryptionKey()); } + @TestTemplate + @ExtendWith(TestAllImplementations.class) + public void decryptMessageAndReadBeyondEndTest() throws Exception { + final String encryptedMessage = TestKeys.MSG_SIGN_CRYPT_JULIET_JULIET; + + final ConsumerOptions options = new ConsumerOptions() + .addDecryptionKey(juliet) + .addVerificationCert(KeyRingUtils.publicKeyRingFrom(juliet)); + + try (final DecryptionStream decryptor = PGPainless.decryptAndOrVerify() + .onInputStream(new ByteArrayInputStream(encryptedMessage.getBytes())) + .withOptions(options); + final ByteArrayOutputStream toPlain = new ByteArrayOutputStream()) { + Streams.pipeAll(decryptor, toPlain); + assertEquals(-1, decryptor.read()); + } + } + @TestTemplate @ExtendWith(TestAllImplementations.class) public void decryptMessageAndVerifySignatureByteByByteTest() throws Exception { From b7e8b56e3d881ce74bd36c010fa4758112374749 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Mon, 27 Nov 2023 13:26:41 +0100 Subject: [PATCH 09/40] Please the checkstyle checker --- .../decryption_verification/DecryptAndVerifyMessageTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/DecryptAndVerifyMessageTest.java b/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/DecryptAndVerifyMessageTest.java index 69a6a2e2..dec10c0a 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/DecryptAndVerifyMessageTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/DecryptAndVerifyMessageTest.java @@ -92,10 +92,10 @@ public class DecryptAndVerifyMessageTest { .addDecryptionKey(juliet) .addVerificationCert(KeyRingUtils.publicKeyRingFrom(juliet)); - try (final DecryptionStream decryptor = PGPainless.decryptAndOrVerify() + try (DecryptionStream decryptor = PGPainless.decryptAndOrVerify() .onInputStream(new ByteArrayInputStream(encryptedMessage.getBytes())) .withOptions(options); - final ByteArrayOutputStream toPlain = new ByteArrayOutputStream()) { + ByteArrayOutputStream toPlain = new ByteArrayOutputStream()) { Streams.pipeAll(decryptor, toPlain); assertEquals(-1, decryptor.read()); } From 4f85a29e0ca126826692cfc1c4d1777d3e7fa5c4 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Thu, 30 Nov 2023 20:04:22 +0100 Subject: [PATCH 10/40] Backport f39d2c5566a30515a3879eae465ddfb113e37738 Prevent subkey binding signature from predating subkey Fixes #419 --- .../pgpainless/key/generation/KeyRingBuilder.java | 12 ++++++++++-- .../secretkeyring/SecretKeyRingEditor.java | 3 ++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeyRingBuilder.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeyRingBuilder.java index 208c17b6..346837c7 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeyRingBuilder.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeyRingBuilder.java @@ -304,6 +304,16 @@ public class KeyRingBuilder implements KeyRingBuilderInterface { public static PGPKeyPair generateKeyPair(KeySpec spec) throws NoSuchAlgorithmException, PGPException, InvalidAlgorithmParameterException { + Date keyCreationDate = spec.getKeyCreationDate(); + if (keyCreationDate == null) { + keyCreationDate = new Date(); + } + return generateKeyPair(spec, keyCreationDate); + } + + public static PGPKeyPair generateKeyPair(KeySpec spec, Date keyCreationDate) + throws NoSuchAlgorithmException, PGPException, + InvalidAlgorithmParameterException { KeyType type = spec.getKeyType(); KeyPairGenerator certKeyGenerator = KeyPairGenerator.getInstance(type.getName(), ProviderFactory.getProvider()); @@ -312,8 +322,6 @@ public class KeyRingBuilder implements KeyRingBuilderInterface { // Create raw Key Pair KeyPair keyPair = certKeyGenerator.generateKeyPair(); - Date keyCreationDate = spec.getKeyCreationDate() != null ? spec.getKeyCreationDate() : new Date(); - // Form PGP key pair PGPKeyPair pgpKeyPair = ImplementationFactory.getInstance() .getPGPKeyPair(type.getAlgorithm(), keyPair, keyCreationDate); diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditor.java b/pgpainless-core/src/main/java/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditor.java index 663c6e41..a6f30435 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditor.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditor.java @@ -290,6 +290,7 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface { @Override public void modifyHashedSubpackets(SelfSignatureSubpackets hashedSubpackets) { SignatureSubpacketsHelper.applyFrom(keySpec.getSubpackets(), (SignatureSubpackets) hashedSubpackets); + hashedSubpackets.setSignatureCreationTime(referenceTime); } }; @@ -307,7 +308,7 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface { @Nullable SelfSignatureSubpackets.Callback subpacketsCallback, @Nonnull SecretKeyRingProtector secretKeyRingProtector) throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IOException { - PGPKeyPair keyPair = KeyRingBuilder.generateKeyPair(keySpec); + PGPKeyPair keyPair = KeyRingBuilder.generateKeyPair(keySpec, referenceTime); SecretKeyRingProtector subKeyProtector = PasswordBasedSecretKeyRingProtector .forKeyId(keyPair.getKeyID(), subkeyPassphrase); From 38db67df80d6f0822b590e7ef92cc25fbf078a9c Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Thu, 30 Nov 2023 20:09:02 +0100 Subject: [PATCH 11/40] Backport 74c7b025a0aa49f947fedb1753a72bcee4334858 Do not choke on unknown signature subpackets Fixes #418 --- .../signature/subpackets/SignatureSubpacketsHelper.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pgpainless-core/src/main/java/org/pgpainless/signature/subpackets/SignatureSubpacketsHelper.java b/pgpainless-core/src/main/java/org/pgpainless/signature/subpackets/SignatureSubpacketsHelper.java index 8af60a03..7f105a85 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/signature/subpackets/SignatureSubpacketsHelper.java +++ b/pgpainless-core/src/main/java/org/pgpainless/signature/subpackets/SignatureSubpacketsHelper.java @@ -35,7 +35,13 @@ public class SignatureSubpacketsHelper { public static SignatureSubpackets applyFrom(PGPSignatureSubpacketVector vector, SignatureSubpackets subpackets) { for (SignatureSubpacket subpacket : vector.toArray()) { - org.pgpainless.algorithm.SignatureSubpacket type = org.pgpainless.algorithm.SignatureSubpacket.requireFromCode(subpacket.getType()); + org.pgpainless.algorithm.SignatureSubpacket type = org.pgpainless.algorithm.SignatureSubpacket.fromCode(subpacket.getType()); + if (type == null) { + // Unknown subpacket, ignore and just add to the residuals + subpackets.addResidualSubpacket(subpacket); + continue; + } + switch (type) { case signatureCreationTime: case issuerKeyId: From 5a343a39d374218b0c2f33d17c1129594beca9da Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Thu, 30 Nov 2023 20:13:22 +0100 Subject: [PATCH 12/40] Backport 97455aa2563b3813376f13b621c0aea1a7efec47 Add test for handling key with unknown signature subpacket --- ...WithUnsupportedSignatureSubpacketTest.java | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 pgpainless-core/src/test/java/org/pgpainless/key/KeyWithUnsupportedSignatureSubpacketTest.java diff --git a/pgpainless-core/src/test/java/org/pgpainless/key/KeyWithUnsupportedSignatureSubpacketTest.java b/pgpainless-core/src/test/java/org/pgpainless/key/KeyWithUnsupportedSignatureSubpacketTest.java new file mode 100644 index 00000000..82cb8d2a --- /dev/null +++ b/pgpainless-core/src/test/java/org/pgpainless/key/KeyWithUnsupportedSignatureSubpacketTest.java @@ -0,0 +1,43 @@ +// SPDX-FileCopyrightText: 2023 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +package org.pgpainless.key; + +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.PGPSecretKeyRing; +import org.junit.jupiter.api.Test; +import org.pgpainless.PGPainless; +import org.pgpainless.key.protection.SecretKeyRingProtector; + +import java.io.IOException; +import java.util.Date; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +public class KeyWithUnsupportedSignatureSubpacketTest { + + @Test + public void testCanSetExpirationDateOnKeyContainingUnknownSubpacket34() throws IOException, PGPException { + String KEY = "-----BEGIN PGP PRIVATE KEY BLOCK-----\n" + + "\n" + + "lFgEZWiyNhYJKwYBBAHaRw8BAQdA71QipJ0CAqOEqQWjuoQE4E7LarKSrNDwE/6K\n" + + "bQNrCLwAAQCtJ8kVG2AmbDfdVtr/7Ag+yBh0oCvjRvyUCOyIbruOeg+6tClTdWJw\n" + + "YWNrZXQzNCBUZXN0S2V5IDx0ZXN0QHBncGFpbmxlc3Mub3JnPoiTBBMWCgA7FiEE\n" + + "zhy5yrnZYU/iBza4G03SQVuWqx0FAmVosjYCGwMFCwkIBwICIgIGFQoJCAsCBBYC\n" + + "AwECHgcCF4AACgkQG03SQVuWqx1UGgD+IYLeh9t5eJCEnzueuOTYnTnrzyhnLgm9\n" + + "dw5qwMXU8VQA/28GCOb7610hyjiBbrrcshkWAKuMwp8bUSz5FOeS5cQEnF0EZWiy\n" + + "NhIKKwYBBAGXVQEFAQEHQK99ClLDYtn0I2b6Y26NhaL0RWcrNoI/ci0xgXEK2L0Y\n" + + "AwEIBwAA/06qciQHI0v7MP2LMWm/ZuTJwzlPqV8VsBhrDMyUPUD4D52IeAQYFgoA\n" + + "IBYhBM4cucq52WFP4gc2uBtN0kFblqsdBQJlaLI2AhsMAAoJEBtN0kFblqsdRQ0A\n" + + "/iUJ/Fp+D2RjZL+aiwByIxPCVvMJ7a28+GQGjg3hsU2BAP474dfOOVZiTDLWWxsB\n" + + "wxfzOAQxXDhgR9xd/Lk3MNJxDg==\n" + + "=YAt0\n" + + "-----END PGP PRIVATE KEY BLOCK-----"; + PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(KEY); + assertNotNull(secretKeys); + PGPainless.modifyKeyRing(secretKeys) + .setExpirationDate(new Date(), SecretKeyRingProtector.unprotectedKeys()) + .done(); + } +} From 160e42c32b336e8a2d6c35a3bf1c4f9b459bffac Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Thu, 30 Nov 2023 20:26:35 +0100 Subject: [PATCH 13/40] Bump BC to 1.77 --- version.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.gradle b/version.gradle index ad7e1c18..6f98417f 100644 --- a/version.gradle +++ b/version.gradle @@ -8,7 +8,7 @@ allprojects { isSnapshot = true pgpainlessMinAndroidSdk = 10 javaSourceCompatibility = 1.8 - bouncyCastleVersion = '1.76' + bouncyCastleVersion = '1.77' bouncyPgVersion = bouncyCastleVersion junitVersion = '5.8.2' logbackVersion = '1.2.11' From 2f67df57df0b421691989a051fa8bd2cdeb324da Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Thu, 30 Nov 2023 20:42:20 +0100 Subject: [PATCH 14/40] Bump logback to 1.4.13 --- version.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.gradle b/version.gradle index 6f98417f..3421d7dc 100644 --- a/version.gradle +++ b/version.gradle @@ -11,7 +11,7 @@ allprojects { bouncyCastleVersion = '1.77' bouncyPgVersion = bouncyCastleVersion junitVersion = '5.8.2' - logbackVersion = '1.2.11' + logbackVersion = '1.4.13' mockitoVersion = '4.5.1' slf4jVersion = '1.7.36' sopJavaVersion = '7.0.1' From 8ec9f49b869268aa6876cbc0023113dbc915a543 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Thu, 30 Nov 2023 20:46:02 +0100 Subject: [PATCH 15/40] Update CHANGELOG --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d726fc2c..08920bc1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,14 @@ SPDX-License-Identifier: CC0-1.0 # PGPainless Changelog +## 1.6.4-SNAPSHOT +- Bump `bcpg-jdk8on` to `1.77` +- Bump `bcprov-jdk18on` to `1.77` +- Bump `logback-core` and `logback-classic` to `1.4.13` +- Properly feed EOS tokens to the pushdown automaton when reaching the end of stream (thanks @iNPUTmice) +- Do not choke on unknown signature subpackets (thanks @Jerbell) +- Prevent timing issues resuting in subkey binding signatures predating the subkey (@thanks Jerbell) + ## 1.6.3 - Bump `sop-java` to `7.0.1` - `decrypt --verify-with`: Fix to not throw `NoSignature` exception (exit code 3) if `VERIFICATIONS` is empty From 1981af77b29a454f27de46098aa6e83356357441 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Thu, 30 Nov 2023 20:51:36 +0100 Subject: [PATCH 16/40] PGPainless 1.6.4 --- CHANGELOG.md | 2 +- README.md | 2 +- pgpainless-sop/README.md | 4 ++-- version.gradle | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 08920bc1..81386330 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ SPDX-License-Identifier: CC0-1.0 # PGPainless Changelog -## 1.6.4-SNAPSHOT +## 1.6.4 - Bump `bcpg-jdk8on` to `1.77` - Bump `bcprov-jdk18on` to `1.77` - Bump `logback-core` and `logback-classic` to `1.4.13` diff --git a/README.md b/README.md index 7f193370..60c64287 100644 --- a/README.md +++ b/README.md @@ -191,7 +191,7 @@ repositories { } dependencies { - implementation 'org.pgpainless:pgpainless-core:1.6.3' + implementation 'org.pgpainless:pgpainless-core:1.6.4' } ``` diff --git a/pgpainless-sop/README.md b/pgpainless-sop/README.md index 12bdaec5..3778560b 100644 --- a/pgpainless-sop/README.md +++ b/pgpainless-sop/README.md @@ -23,7 +23,7 @@ To start using pgpainless-sop in your code, include the following lines in your ... dependencies { ... - implementation "org.pgpainless:pgpainless-sop:1.6.3" + implementation "org.pgpainless:pgpainless-sop:1.6.4" ... } @@ -34,7 +34,7 @@ dependencies { org.pgpainless pgpainless-sop - 1.6.3 + 1.6.4 ... diff --git a/version.gradle b/version.gradle index 3421d7dc..9e0912f8 100644 --- a/version.gradle +++ b/version.gradle @@ -5,7 +5,7 @@ allprojects { ext { shortVersion = '1.6.4' - isSnapshot = true + isSnapshot = false pgpainlessMinAndroidSdk = 10 javaSourceCompatibility = 1.8 bouncyCastleVersion = '1.77' From 4d1d8083d36bc943d7efe13d4f169654b85f0f26 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Thu, 30 Nov 2023 20:53:28 +0100 Subject: [PATCH 17/40] PGPainless 1.6.5-SNAPSHOT --- version.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version.gradle b/version.gradle index 9e0912f8..c2f773da 100644 --- a/version.gradle +++ b/version.gradle @@ -4,8 +4,8 @@ allprojects { ext { - shortVersion = '1.6.4' - isSnapshot = false + shortVersion = '1.6.5' + isSnapshot = true pgpainlessMinAndroidSdk = 10 javaSourceCompatibility = 1.8 bouncyCastleVersion = '1.77' From 2c271178cd751e669ddc4ebdd5f3e36a001539b1 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Thu, 7 Dec 2023 17:38:01 +0100 Subject: [PATCH 18/40] Allow null as keyExpirationTime (no expiry) --- .../subpackets/SelfSignatureSubpackets.java | 6 +++--- .../signature/subpackets/SignatureSubpackets.java | 12 ++++++++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/pgpainless-core/src/main/java/org/pgpainless/signature/subpackets/SelfSignatureSubpackets.java b/pgpainless-core/src/main/java/org/pgpainless/signature/subpackets/SelfSignatureSubpackets.java index 02cc5e93..92bf02b3 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/signature/subpackets/SelfSignatureSubpackets.java +++ b/pgpainless-core/src/main/java/org/pgpainless/signature/subpackets/SelfSignatureSubpackets.java @@ -46,11 +46,11 @@ public interface SelfSignatureSubpackets extends BaseSignatureSubpackets { SelfSignatureSubpackets setPrimaryUserId(@Nullable PrimaryUserID primaryUserId); - SelfSignatureSubpackets setKeyExpirationTime(@Nonnull PGPPublicKey key, @Nonnull Date keyExpirationTime); + SelfSignatureSubpackets setKeyExpirationTime(@Nonnull PGPPublicKey key, @Nullable Date keyExpirationTime); - SelfSignatureSubpackets setKeyExpirationTime(@Nonnull Date keyCreationTime, @Nonnull Date keyExpirationTime); + SelfSignatureSubpackets setKeyExpirationTime(@Nonnull Date keyCreationTime, @Nullable Date keyExpirationTime); - SelfSignatureSubpackets setKeyExpirationTime(boolean isCritical, @Nonnull Date keyCreationTime, @Nonnull Date keyExpirationTime); + SelfSignatureSubpackets setKeyExpirationTime(boolean isCritical, @Nonnull Date keyCreationTime, @Nullable Date keyExpirationTime); SelfSignatureSubpackets setKeyExpirationTime(boolean isCritical, long secondsFromCreationToExpiration); diff --git a/pgpainless-core/src/main/java/org/pgpainless/signature/subpackets/SignatureSubpackets.java b/pgpainless-core/src/main/java/org/pgpainless/signature/subpackets/SignatureSubpackets.java index d0466b6a..be65dd7e 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/signature/subpackets/SignatureSubpackets.java +++ b/pgpainless-core/src/main/java/org/pgpainless/signature/subpackets/SignatureSubpackets.java @@ -271,18 +271,22 @@ public class SignatureSubpackets } @Override - public SignatureSubpackets setKeyExpirationTime(@Nonnull PGPPublicKey key, @Nonnull Date keyExpirationTime) { + public SignatureSubpackets setKeyExpirationTime(@Nonnull PGPPublicKey key, @Nullable Date keyExpirationTime) { return setKeyExpirationTime(key.getCreationTime(), keyExpirationTime); } @Override - public SignatureSubpackets setKeyExpirationTime(@Nonnull Date keyCreationTime, @Nonnull Date keyExpirationTime) { + public SignatureSubpackets setKeyExpirationTime(@Nonnull Date keyCreationTime, @Nullable Date keyExpirationTime) { return setKeyExpirationTime(true, keyCreationTime, keyExpirationTime); } @Override - public SignatureSubpackets setKeyExpirationTime(boolean isCritical, @Nonnull Date keyCreationTime, @Nonnull Date keyExpirationTime) { - return setKeyExpirationTime(isCritical, (keyExpirationTime.getTime() / 1000) - (keyCreationTime.getTime() / 1000)); + public SignatureSubpackets setKeyExpirationTime(boolean isCritical, @Nonnull Date keyCreationTime, @Nullable Date keyExpirationTime) { + if (keyExpirationTime != null) { + return setKeyExpirationTime(isCritical, (keyExpirationTime.getTime() / 1000) - (keyCreationTime.getTime() / 1000)); + } else { + return setKeyExpirationTime(isCritical, 0L); + } } @Override From e06f60f62c13605806413b24e37d912c62008da0 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Thu, 7 Dec 2023 17:38:36 +0100 Subject: [PATCH 19/40] Add method to change the expiration time of subkeys --- .../secretkeyring/SecretKeyRingEditor.java | 71 ++++++++++++++ .../SecretKeyRingEditorInterface.java | 17 ++++ .../ChangeSubkeyExpirationTimeTest.java | 93 +++++++++++++++++++ 3 files changed, 181 insertions(+) create mode 100644 pgpainless-core/src/test/java/org/pgpainless/key/modification/ChangeSubkeyExpirationTimeTest.java diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditor.java b/pgpainless-core/src/main/java/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditor.java index a6f30435..a8c569a2 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditor.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditor.java @@ -47,6 +47,7 @@ import org.pgpainless.key.protection.PasswordBasedSecretKeyRingProtector; import org.pgpainless.key.protection.SecretKeyRingProtector; import org.pgpainless.key.protection.UnprotectedKeysProtector; import org.pgpainless.key.protection.passphrase_provider.SolitaryPassphraseProvider; +import org.pgpainless.key.util.KeyIdUtil; import org.pgpainless.key.util.KeyRingUtils; import org.pgpainless.key.util.RevocationAttributes; import org.pgpainless.signature.builder.DirectKeySelfSignatureBuilder; @@ -609,6 +610,25 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface { return this; } + @Override + public SecretKeyRingEditorInterface setExpirationDateOfSubkey(@Nullable Date expiration, long keyId, @Nonnull SecretKeyRingProtector secretKeyRingProtector) throws PGPException { + // is primary key + if (keyId == secretKeyRing.getPublicKey().getKeyID()) { + return setExpirationDate(expiration, secretKeyRingProtector); + } + + // is subkey + PGPPublicKey subkey = secretKeyRing.getPublicKey(keyId); + if (subkey != null) { + PGPSignature prevBinding = PGPainless.inspectKeyRing(secretKeyRing).getCurrentSubkeyBindingSignature(keyId); + PGPSignature bindingSig = reissueSubkeyBindingSignature(subkey, expiration, secretKeyRingProtector, prevBinding); + secretKeyRing = KeyRingUtils.injectCertification(secretKeyRing, subkey, bindingSig); + } else { + throw new NoSuchElementException("No subkey with ID " + KeyIdUtil.formatKeyId(keyId) + " found."); + } + return this; + } + @Override public PGPPublicKeyRing createMinimalRevocationCertificate( @Nonnull SecretKeyRingProtector secretKeyRingProtector, @@ -699,6 +719,57 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface { return builder.build(publicKey); } + private PGPSignature reissueSubkeyBindingSignature( + PGPPublicKey subkey, + Date expiration, + SecretKeyRingProtector secretKeyRingProtector, + PGPSignature prevSubkeyBindingSignature) + throws PGPException { + if (subkey == null) { + throw new IllegalArgumentException("Subkey MUST NOT be null."); + } + if (prevSubkeyBindingSignature == null) { + throw new IllegalArgumentException("Previous subkey binding signature for " + + KeyIdUtil.formatKeyId(subkey.getKeyID()) + " MUST NOT be null."); + } + PGPPublicKey primaryKey = secretKeyRing.getPublicKey(); + PGPSecretKey secretPrimaryKey = secretKeyRing.getSecretKey(); + PGPSecretKey secretSubkey = secretKeyRing.getSecretKey(subkey.getKeyID()); + + if (secretPrimaryKey == null) { + throw new NoSuchElementException("Secret Key Ring does not contain secret-key component for the primary key."); + } + + SubkeyBindingSignatureBuilder builder = new SubkeyBindingSignatureBuilder( + secretPrimaryKey, secretKeyRingProtector, prevSubkeyBindingSignature); + SelfSignatureSubpackets subpackets = builder.getHashedSubpackets(); + if (referenceTime != null) { + subpackets.setSignatureCreationTime(referenceTime); + } + // Set expiration + subpackets.setKeyExpirationTime(subkey, expiration); + subpackets.setSignatureExpirationTime(null); // avoid copying sig exp time + + List previousKeyFlags = SignatureSubpacketsUtil.parseKeyFlags(prevSubkeyBindingSignature); + if (previousKeyFlags != null && previousKeyFlags.contains(KeyFlag.SIGN_DATA)) { + if (secretSubkey == null) { + throw new NoSuchElementException("Secret keyring does not contain secret-key component for subkey " + + KeyIdUtil.formatKeyId(subkey.getKeyID())); + } + + // Create new embedded back-sig + subpackets.clearEmbeddedSignatures(); + try { + subpackets.addEmbeddedSignature( + new PrimaryKeyBindingSignatureBuilder(secretSubkey, secretKeyRingProtector) + .build(primaryKey)); + } catch (IOException e) { + throw new PGPException("Cannot add embedded primary-key back signature.", e); + } + } + return builder.build(subkey); + } + private PGPSignature getPreviousDirectKeySignature() { KeyRingInfo info = PGPainless.inspectKeyRing(secretKeyRing, referenceTime); return info.getLatestDirectKeySelfSignature(); diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditorInterface.java b/pgpainless-core/src/main/java/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditorInterface.java index dd7ed499..f746934e 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditorInterface.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditorInterface.java @@ -469,6 +469,23 @@ public interface SecretKeyRingEditorInterface { @Nonnull SecretKeyRingProtector secretKeyRingProtector) throws PGPException; + /** + * Set the expiration date for the subkey identified by the given keyId to the given expiration date. + * If the key is supposed to never expire, then an expiration date of null is expected. + * + * @param expiration new expiration date of null + * @param keyId id of the subkey + * @param secretKeyRingProtector to unlock the secret key + * @return the builder + * @throws PGPException in case we cannot generate a new subkey-binding or self-signature with the + * changed expiration date + */ + SecretKeyRingEditorInterface setExpirationDateOfSubkey( + @Nullable Date expiration, + long keyId, + @Nonnull SecretKeyRingProtector secretKeyRingProtector) + throws PGPException; + /** * Create a minimal, self-authorizing revocation certificate, containing only the primary key * and a revocation signature. diff --git a/pgpainless-core/src/test/java/org/pgpainless/key/modification/ChangeSubkeyExpirationTimeTest.java b/pgpainless-core/src/test/java/org/pgpainless/key/modification/ChangeSubkeyExpirationTimeTest.java new file mode 100644 index 00000000..c550e376 --- /dev/null +++ b/pgpainless-core/src/test/java/org/pgpainless/key/modification/ChangeSubkeyExpirationTimeTest.java @@ -0,0 +1,93 @@ +// SPDX-FileCopyrightText: 2023 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +package org.pgpainless.key.modification; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +import java.io.IOException; +import java.security.InvalidAlgorithmParameterException; +import java.security.NoSuchAlgorithmException; +import java.util.Date; + +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.PGPPublicKey; +import org.bouncycastle.openpgp.PGPSecretKeyRing; +import org.junit.JUtils; +import org.junit.jupiter.api.Test; +import org.pgpainless.PGPainless; +import org.pgpainless.algorithm.EncryptionPurpose; +import org.pgpainless.key.OpenPgpFingerprint; +import org.pgpainless.key.OpenPgpV4Fingerprint; +import org.pgpainless.key.protection.SecretKeyRingProtector; +import org.pgpainless.util.DateUtil; + +public class ChangeSubkeyExpirationTimeTest { + + @Test + public void changeExpirationTimeOfSubkey() throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException { + PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing().modernKeyRing("Alice"); + Date now = secretKeys.getPublicKey().getCreationTime(); + Date inAnHour = new Date(now.getTime() + 1000 * 60 * 60); + PGPPublicKey encryptionKey = PGPainless.inspectKeyRing(secretKeys) + .getEncryptionSubkeys(EncryptionPurpose.ANY).get(0); + secretKeys = PGPainless.modifyKeyRing(secretKeys) + .setExpirationDateOfSubkey( + inAnHour, + encryptionKey.getKeyID(), + SecretKeyRingProtector.unprotectedKeys()) + .done(); + + JUtils.assertDateEquals(inAnHour, PGPainless.inspectKeyRing(secretKeys) + .getSubkeyExpirationDate(OpenPgpFingerprint.of(encryptionKey))); + } + + @Test + public void changeExpirationTimeOfExpiredSubkey() throws PGPException, IOException { + PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing( + "-----BEGIN PGP PRIVATE KEY BLOCK-----\n" + + "Version: PGPainless\n" + + "Comment: CA52 4D5D E3D8 9CD9 105B BA45 3761 076B C6B5 3000\n" + + "Comment: Alice \n" + + "\n" + + "lFgEZXHykRYJKwYBBAHaRw8BAQdATArrVxPEpuA/wcayAxRl/v1tIYJSe4MCA/fO\n" + + "84CFgpcAAP9uZkLjoBIQAjUTEiS8Wk3sui3u4mJ4WVQEpNhQSpq37g8gtBxBbGlj\n" + + "ZSA8YWxpY2VAcGdwYWlubGVzcy5vcmc+iJUEExYKAEcFAmVx8pIJEDdhB2vGtTAA\n" + + "FiEEylJNXePYnNkQW7pFN2EHa8a1MAACngECmwEFFgIDAQAECwkIBwUVCgkICwWJ\n" + + "CWYBgAKZAQAAG3oA/0iJbwyjGOTa2RlgBKdmFjlBG5uwMGheKge/aZBbdUd8AQCB\n" + + "8NFWmyLlne4hDMM2g8RFf/W156wnyTH7jTQLx2sZDJxYBGVx8pIWCSsGAQQB2kcP\n" + + "AQEHQLQt6ns7yTxLvIWXqFCekh6QEvUumhHvCTjZPXa/UxCNAAEA+FHhZ1uik6PN\n" + + "Pwli9Tp9QGddf3pwQw+OL/K7gpZO3sgQHYjVBBgWCgB9BQJlcfKSAp4BApsCBRYC\n" + + "AwEABAsJCAcFFQoJCAtfIAQZFgoABgUCZXHykgAKCRCRKlHdDPaYKjyZAQD10Km4\n" + + "Qs37yF9bntS+z9Va7AMUuBlzYF5H/nXCRuqQTAEA60q++7Xwj94yLfoAfxH0V6Wd\n" + + "L2rDJCDZ3FFMlycToQMACgkQN2EHa8a1MADmDgD9EGzH6pPYRW5vWQGXNsr7PMWK\n" + + "LlBnevc0DaVWEHTu9tcA/iezQ9R+A90qcE1+HeNIJbSB89yIoJje2vePRV/JakAI\n" + + "nF0EZXHykhIKKwYBBAGXVQEFAQEHQOiLc02OQJD9qdpsyR6bJ52Cu8rUMlEJOELz\n" + + "1858OoQyAwEIBwAA/3YkHGmnVaQvUpSwlCInOvHvjLNLH9b9Lh/OxiuSoMgIEASI\n" + + "dQQYFgoAHQUCZXHykgKeAQKbDAUWAgMBAAQLCQgHBRUKCQgLAAoJEDdhB2vGtTAA\n" + + "1nkBAPAUcHxI1O+fE/QzuLANLHDeWc3Mc09KKnWoTkt/kk5VAQCIPlKQAcmmKdYE\n" + + "Tiz8woSKLQKswKr/jVMqnUiGPsU/DoiSBBgWCgBECRA3YQdrxrUwABYhBMpSTV3j\n" + + "2JzZEFu6RTdhB2vGtTAABYJlcfL6Ap4BApsMBRYCAwEABAsJCAcFFQoJCAsFiQAA\n" + + "AGgAAMNmAQDN/TML2zdgBNkfh7TIqbI4Flx54Yi7qEjSXg0Z+tszHgD/e1Bf+xEs\n" + + "BC9ewVsyQsnj3B0FliGYaPiQeoY/FGBmYQs=\n" + + "=5Ur6\n" + + "-----END PGP PRIVATE KEY BLOCK-----" + ); + assertNotNull(secretKeys); + + // subkey is expired at 2023-12-07 16:29:46 UTC + OpenPgpFingerprint encryptionSubkey = new OpenPgpV4Fingerprint("2E541354A23C9943375EC27A3EF133ED8720D636"); + JUtils.assertDateEquals( + DateUtil.parseUTCDate("2023-12-07 16:29:46 UTC"), + PGPainless.inspectKeyRing(secretKeys).getSubkeyExpirationDate(encryptionSubkey)); + + // re-validate the subkey by setting its expiry to null (no expiry) + secretKeys = PGPainless.modifyKeyRing(secretKeys) + .setExpirationDateOfSubkey(null, encryptionSubkey.getKeyId(), SecretKeyRingProtector.unprotectedKeys()) + .done(); + + assertNull(PGPainless.inspectKeyRing(secretKeys).getSubkeyExpirationDate(encryptionSubkey)); + } +} From d0c38601c967cad755fcfa0165e9b2b19bfe3b40 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Thu, 7 Dec 2023 17:39:55 +0100 Subject: [PATCH 20/40] Update changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 81386330..6cb2aa4d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ SPDX-License-Identifier: CC0-1.0 # PGPainless Changelog +## 1.6.5-SNAPSHOT +- Add `SecretKeyRingEditor.setExpirationDateOfSubkey()` + ## 1.6.4 - Bump `bcpg-jdk8on` to `1.77` - Bump `bcprov-jdk18on` to `1.77` From d92672bd85d97e499158f94b1937df68851186f3 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Fri, 15 Dec 2023 17:35:50 +0100 Subject: [PATCH 21/40] PGPainless 1.6.5 --- CHANGELOG.md | 4 ++-- README.md | 2 +- pgpainless-sop/README.md | 4 ++-- version.gradle | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6cb2aa4d..09e16001 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ SPDX-License-Identifier: CC0-1.0 # PGPainless Changelog -## 1.6.5-SNAPSHOT +## 1.6.5 - Add `SecretKeyRingEditor.setExpirationDateOfSubkey()` ## 1.6.4 @@ -14,7 +14,7 @@ SPDX-License-Identifier: CC0-1.0 - Bump `logback-core` and `logback-classic` to `1.4.13` - Properly feed EOS tokens to the pushdown automaton when reaching the end of stream (thanks @iNPUTmice) - Do not choke on unknown signature subpackets (thanks @Jerbell) -- Prevent timing issues resuting in subkey binding signatures predating the subkey (@thanks Jerbell) +- Prevent timing issues resulting in subkey binding signatures predating the subkey (@thanks Jerbell) ## 1.6.3 - Bump `sop-java` to `7.0.1` diff --git a/README.md b/README.md index 60c64287..8a4f17b3 100644 --- a/README.md +++ b/README.md @@ -191,7 +191,7 @@ repositories { } dependencies { - implementation 'org.pgpainless:pgpainless-core:1.6.4' + implementation 'org.pgpainless:pgpainless-core:1.6.5' } ``` diff --git a/pgpainless-sop/README.md b/pgpainless-sop/README.md index 3778560b..657edd81 100644 --- a/pgpainless-sop/README.md +++ b/pgpainless-sop/README.md @@ -23,7 +23,7 @@ To start using pgpainless-sop in your code, include the following lines in your ... dependencies { ... - implementation "org.pgpainless:pgpainless-sop:1.6.4" + implementation "org.pgpainless:pgpainless-sop:1.6.5" ... } @@ -34,7 +34,7 @@ dependencies { org.pgpainless pgpainless-sop - 1.6.4 + 1.6.5 ... diff --git a/version.gradle b/version.gradle index c2f773da..6c9793ee 100644 --- a/version.gradle +++ b/version.gradle @@ -5,7 +5,7 @@ allprojects { ext { shortVersion = '1.6.5' - isSnapshot = true + isSnapshot = false pgpainlessMinAndroidSdk = 10 javaSourceCompatibility = 1.8 bouncyCastleVersion = '1.77' From 6291729c519261a21761d3e330b4990bc4d8bf0b Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Fri, 15 Dec 2023 17:37:59 +0100 Subject: [PATCH 22/40] PGPainless 1.6.6-SNAPSHOT --- version.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version.gradle b/version.gradle index 6c9793ee..637dca1f 100644 --- a/version.gradle +++ b/version.gradle @@ -4,8 +4,8 @@ allprojects { ext { - shortVersion = '1.6.5' - isSnapshot = false + shortVersion = '1.6.6' + isSnapshot = true pgpainlessMinAndroidSdk = 10 javaSourceCompatibility = 1.8 bouncyCastleVersion = '1.77' From 73917678e1865921a2d0b20f392eba3bc22c5b6d Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Fri, 2 Feb 2024 22:03:27 +0100 Subject: [PATCH 23/40] Downgrade logback to 1.2.13 --- version.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.gradle b/version.gradle index 637dca1f..36b3da4c 100644 --- a/version.gradle +++ b/version.gradle @@ -11,7 +11,7 @@ allprojects { bouncyCastleVersion = '1.77' bouncyPgVersion = bouncyCastleVersion junitVersion = '5.8.2' - logbackVersion = '1.4.13' + logbackVersion = '1.2.13' mockitoVersion = '4.5.1' slf4jVersion = '1.7.36' sopJavaVersion = '7.0.1' From 8aa95777d784c8f9b9c26042ac74bd5fa2f85460 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Fri, 2 Feb 2024 22:06:11 +0100 Subject: [PATCH 24/40] PGPainless 1.6.6 --- CHANGELOG.md | 3 +++ README.md | 2 +- pgpainless-sop/README.md | 4 ++-- version.gradle | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 09e16001..32f95280 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ SPDX-License-Identifier: CC0-1.0 # PGPainless Changelog +## 1.6.6 +- Downgrade `logback-core` and `logback-classic` to `1.2.13` to fix #426 + ## 1.6.5 - Add `SecretKeyRingEditor.setExpirationDateOfSubkey()` diff --git a/README.md b/README.md index 8a4f17b3..484234d8 100644 --- a/README.md +++ b/README.md @@ -191,7 +191,7 @@ repositories { } dependencies { - implementation 'org.pgpainless:pgpainless-core:1.6.5' + implementation 'org.pgpainless:pgpainless-core:1.6.6' } ``` diff --git a/pgpainless-sop/README.md b/pgpainless-sop/README.md index 657edd81..e31f993b 100644 --- a/pgpainless-sop/README.md +++ b/pgpainless-sop/README.md @@ -23,7 +23,7 @@ To start using pgpainless-sop in your code, include the following lines in your ... dependencies { ... - implementation "org.pgpainless:pgpainless-sop:1.6.5" + implementation "org.pgpainless:pgpainless-sop:1.6.6" ... } @@ -34,7 +34,7 @@ dependencies { org.pgpainless pgpainless-sop - 1.6.5 + 1.6.6 ... diff --git a/version.gradle b/version.gradle index 36b3da4c..cfa40d28 100644 --- a/version.gradle +++ b/version.gradle @@ -5,7 +5,7 @@ allprojects { ext { shortVersion = '1.6.6' - isSnapshot = true + isSnapshot = false pgpainlessMinAndroidSdk = 10 javaSourceCompatibility = 1.8 bouncyCastleVersion = '1.77' From 8abd8e8708e4f893960111cb523c722de85cb15a Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Fri, 2 Feb 2024 22:08:37 +0100 Subject: [PATCH 25/40] PGPainless 1.6.7-SNAPSHOT --- version.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version.gradle b/version.gradle index cfa40d28..d067fe4f 100644 --- a/version.gradle +++ b/version.gradle @@ -4,8 +4,8 @@ allprojects { ext { - shortVersion = '1.6.6' - isSnapshot = false + shortVersion = '1.6.7' + isSnapshot = true pgpainlessMinAndroidSdk = 10 javaSourceCompatibility = 1.8 bouncyCastleVersion = '1.77' From 9cf15e3d7c839a4112de7694f2614df0777196dc Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Sun, 17 Mar 2024 17:11:28 +0100 Subject: [PATCH 26/40] Fix OOM when detached signing large files Fixes #432 --- .../org/pgpainless/sop/DetachedSignImpl.java | 5 ++--- .../org/pgpainless/sop/NullOutputStream.java | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 pgpainless-sop/src/main/java/org/pgpainless/sop/NullOutputStream.java diff --git a/pgpainless-sop/src/main/java/org/pgpainless/sop/DetachedSignImpl.java b/pgpainless-sop/src/main/java/org/pgpainless/sop/DetachedSignImpl.java index c32cb219..4f74b9ee 100644 --- a/pgpainless-sop/src/main/java/org/pgpainless/sop/DetachedSignImpl.java +++ b/pgpainless-sop/src/main/java/org/pgpainless/sop/DetachedSignImpl.java @@ -4,7 +4,6 @@ package org.pgpainless.sop; -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -92,10 +91,10 @@ public class DetachedSignImpl implements DetachedSign { } } - ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + OutputStream sink = new NullOutputStream(); try { EncryptionStream signingStream = PGPainless.encryptAndOrSign() - .onOutputStream(buffer) + .onOutputStream(sink) .withOptions(ProducerOptions.sign(signingOptions) .setAsciiArmor(armor)); diff --git a/pgpainless-sop/src/main/java/org/pgpainless/sop/NullOutputStream.java b/pgpainless-sop/src/main/java/org/pgpainless/sop/NullOutputStream.java new file mode 100644 index 00000000..9977ba28 --- /dev/null +++ b/pgpainless-sop/src/main/java/org/pgpainless/sop/NullOutputStream.java @@ -0,0 +1,17 @@ +// SPDX-FileCopyrightText: 2024 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +package org.pgpainless.sop; + +import java.io.OutputStream; + +/** + * {@link OutputStream} that simply discards bytes written to it. + */ +public class NullOutputStream extends OutputStream { + @Override + public void write(int b) { + // NOP + } +} From caeeaf67514a78f92d70ed6762d2b05b89d6ce4b Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Sun, 17 Mar 2024 17:22:15 +0100 Subject: [PATCH 27/40] Update changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 32f95280..de3b10f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ SPDX-License-Identifier: CC0-1.0 # PGPainless Changelog +## 1.6.7-SNAPSHOT +- Fix OOM error when detached-signing large amounts of data (fix #432) + ## 1.6.6 - Downgrade `logback-core` and `logback-classic` to `1.2.13` to fix #426 From 72242304938511e5bc8320dee8ec104d72ea1838 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Tue, 19 Mar 2024 15:09:21 +0100 Subject: [PATCH 28/40] Move CachingPublicKeyDataDecryptorFactory to package org.pgpainless.decryption_verification Partially addresses #428 for the 1.6 branch --- .../src/main/java/org/bouncycastle/package-info.java | 8 -------- .../CachingBcPublicKeyDataDecryptorFactory.java | 5 ++--- .../CachingBcPublicKeyDataDecryptorFactoryTest.java | 1 + 3 files changed, 3 insertions(+), 11 deletions(-) delete mode 100644 pgpainless-core/src/main/java/org/bouncycastle/package-info.java rename pgpainless-core/src/main/java/org/{bouncycastle => pgpainless/decryption_verification}/CachingBcPublicKeyDataDecryptorFactory.java (95%) diff --git a/pgpainless-core/src/main/java/org/bouncycastle/package-info.java b/pgpainless-core/src/main/java/org/bouncycastle/package-info.java deleted file mode 100644 index 565bb5f4..00000000 --- a/pgpainless-core/src/main/java/org/bouncycastle/package-info.java +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Paul Schaub -// -// SPDX-License-Identifier: Apache-2.0 - -/** - * Classes which could be upstreamed to BC at some point. - */ -package org.bouncycastle; diff --git a/pgpainless-core/src/main/java/org/bouncycastle/CachingBcPublicKeyDataDecryptorFactory.java b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/CachingBcPublicKeyDataDecryptorFactory.java similarity index 95% rename from pgpainless-core/src/main/java/org/bouncycastle/CachingBcPublicKeyDataDecryptorFactory.java rename to pgpainless-core/src/main/java/org/pgpainless/decryption_verification/CachingBcPublicKeyDataDecryptorFactory.java index 510b0938..9196cc37 100644 --- a/pgpainless-core/src/main/java/org/bouncycastle/CachingBcPublicKeyDataDecryptorFactory.java +++ b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/CachingBcPublicKeyDataDecryptorFactory.java @@ -1,8 +1,8 @@ -// SPDX-FileCopyrightText: 2022 Paul Schaub +// SPDX-FileCopyrightText: 2024 Paul Schaub // // SPDX-License-Identifier: Apache-2.0 -package org.bouncycastle; +package org.pgpainless.decryption_verification; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPPrivateKey; @@ -10,7 +10,6 @@ import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory; import org.bouncycastle.openpgp.operator.bc.BcPublicKeyDataDecryptorFactory; import org.bouncycastle.util.encoders.Base64; import org.bouncycastle.util.encoders.Hex; -import org.pgpainless.decryption_verification.CustomPublicKeyDataDecryptorFactory; import org.pgpainless.key.SubkeyIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/pgpainless-core/src/test/java/org/bouncycastle/CachingBcPublicKeyDataDecryptorFactoryTest.java b/pgpainless-core/src/test/java/org/bouncycastle/CachingBcPublicKeyDataDecryptorFactoryTest.java index b8eab5e4..10cf4b1f 100644 --- a/pgpainless-core/src/test/java/org/bouncycastle/CachingBcPublicKeyDataDecryptorFactoryTest.java +++ b/pgpainless-core/src/test/java/org/bouncycastle/CachingBcPublicKeyDataDecryptorFactoryTest.java @@ -18,6 +18,7 @@ import org.bouncycastle.util.io.Streams; import org.junit.jupiter.api.Test; import org.pgpainless.PGPainless; import org.pgpainless.algorithm.EncryptionPurpose; +import org.pgpainless.decryption_verification.CachingBcPublicKeyDataDecryptorFactory; import org.pgpainless.decryption_verification.ConsumerOptions; import org.pgpainless.decryption_verification.DecryptionStream; import org.pgpainless.key.SubkeyIdentifier; From 0cf7fb6289d7a3316d9f87785f4d1049d4c3d1e7 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Tue, 19 Mar 2024 15:51:09 +0100 Subject: [PATCH 29/40] Add Automatic-Module-Name to pgpainless-core and pgpainless-sop --- pgpainless-core/build.gradle | 7 +++++++ pgpainless-sop/build.gradle | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/pgpainless-core/build.gradle b/pgpainless-core/build.gradle index 830e573d..bab6ecf1 100644 --- a/pgpainless-core/build.gradle +++ b/pgpainless-core/build.gradle @@ -27,3 +27,10 @@ dependencies { // @Nullable, @Nonnull annotations implementation "com.google.code.findbugs:jsr305:3.0.2" } + +// https://docs.gradle.org/current/userguide/java_library_plugin.html#sec:java_library_modular_auto +tasks.named('jar') { + manifest { + attributes('Automatic-Module-Name': 'org.pgpainless.core') + } +} diff --git a/pgpainless-sop/build.gradle b/pgpainless-sop/build.gradle index bb4ddaca..26beec67 100644 --- a/pgpainless-sop/build.gradle +++ b/pgpainless-sop/build.gradle @@ -34,3 +34,10 @@ test { useJUnitPlatform() environment("test.implementation", "sop.testsuite.pgpainless.PGPainlessSopInstanceFactory") } + +// https://docs.gradle.org/current/userguide/java_library_plugin.html#sec:java_library_modular_auto +tasks.named('jar') { + manifest { + attributes('Automatic-Module-Name': 'org.pgpainless.sop') + } +} From 36c29cd167c26ac1210b4d0ac2e83d2be70294d7 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Tue, 19 Mar 2024 15:55:58 +0100 Subject: [PATCH 30/40] Update changelog --- CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index de3b10f2..59c94ced 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,10 @@ SPDX-License-Identifier: CC0-1.0 # PGPainless Changelog ## 1.6.7-SNAPSHOT -- Fix OOM error when detached-signing large amounts of data (fix #432) +- SOP: Fix OOM error when detached-signing large amounts of data (fix #432) +- Move `CachingBcPublicKeyDataDecryptorFactory` from `org.bouncycastle` packet to `org.pgpainless.decryption_verification` to avoid package split (partially addresses #428) +- Basic support for Java Modules for `pgpainless-core` and `pgpainless-sop` + - Added `Automatic-Module-Name` directive to gradle build files ## 1.6.6 - Downgrade `logback-core` and `logback-classic` to `1.2.13` to fix #426 From fc7101cdef6124f07902379adeea03a78b65bbb5 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Thu, 21 Mar 2024 12:37:39 +0100 Subject: [PATCH 31/40] PGPainless 1.6.7 --- CHANGELOG.md | 2 +- README.md | 2 +- SECURITY.md | 2 +- pgpainless-sop/README.md | 4 ++-- version.gradle | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 59c94ced..f4de3afb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ SPDX-License-Identifier: CC0-1.0 # PGPainless Changelog -## 1.6.7-SNAPSHOT +## 1.6.7 - SOP: Fix OOM error when detached-signing large amounts of data (fix #432) - Move `CachingBcPublicKeyDataDecryptorFactory` from `org.bouncycastle` packet to `org.pgpainless.decryption_verification` to avoid package split (partially addresses #428) - Basic support for Java Modules for `pgpainless-core` and `pgpainless-sop` diff --git a/README.md b/README.md index 484234d8..01eab05d 100644 --- a/README.md +++ b/README.md @@ -191,7 +191,7 @@ repositories { } dependencies { - implementation 'org.pgpainless:pgpainless-core:1.6.6' + implementation 'org.pgpainless:pgpainless-core:1.6.7' } ``` diff --git a/SECURITY.md b/SECURITY.md index 2036180a..d668040b 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -32,4 +32,4 @@ Valid security issues will be fixed ASAP. PGPainless has received a security audit by [cure53.de](https://cure53.de) in late 2021. The [penetrationj test and audit](https://cure53.de/pentest-report_pgpainless.pdf) covered PGPainless release candidate 1.0.0-rc6. -Security fixes for discovered flaws were deployed before the final 1.0.0 release. \ No newline at end of file +Security fixes for discovered flaws were deployed before the final 1.0.0 release. diff --git a/pgpainless-sop/README.md b/pgpainless-sop/README.md index e31f993b..d1e1b246 100644 --- a/pgpainless-sop/README.md +++ b/pgpainless-sop/README.md @@ -23,7 +23,7 @@ To start using pgpainless-sop in your code, include the following lines in your ... dependencies { ... - implementation "org.pgpainless:pgpainless-sop:1.6.6" + implementation "org.pgpainless:pgpainless-sop:1.6.7" ... } @@ -34,7 +34,7 @@ dependencies { org.pgpainless pgpainless-sop - 1.6.6 + 1.6.7 ... diff --git a/version.gradle b/version.gradle index d067fe4f..9541010d 100644 --- a/version.gradle +++ b/version.gradle @@ -5,7 +5,7 @@ allprojects { ext { shortVersion = '1.6.7' - isSnapshot = true + isSnapshot = false pgpainlessMinAndroidSdk = 10 javaSourceCompatibility = 1.8 bouncyCastleVersion = '1.77' From 9d3cbf595749b6a9c2af514ef7f8bf0050374cc9 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Thu, 21 Mar 2024 12:40:41 +0100 Subject: [PATCH 32/40] PGPainless 1.6.8-SNAPSHOT --- version.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version.gradle b/version.gradle index 9541010d..2c0f24be 100644 --- a/version.gradle +++ b/version.gradle @@ -4,8 +4,8 @@ allprojects { ext { - shortVersion = '1.6.7' - isSnapshot = false + shortVersion = '1.6.8' + isSnapshot = true pgpainlessMinAndroidSdk = 10 javaSourceCompatibility = 1.8 bouncyCastleVersion = '1.77' From dd7adc8f13506eef564a3fadcb323d08f4f2be96 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Sat, 30 Mar 2024 00:37:51 +0100 Subject: [PATCH 33/40] Fix missing readthedocs theme --- docs/requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/requirements.txt b/docs/requirements.txt index 1d5e0d5b..ab1cf848 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,2 +1,3 @@ myst-parser>=0.17 sphinxcontrib-mermaid>=0.7.1 +sphinx_rtd_theme>=2.0.0 From bbe60ba9dc7ea5b777fb3adb5f186e1d297ce75f Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Thu, 31 Oct 2024 14:23:57 +0100 Subject: [PATCH 34/40] Bump sop-java to 7.0.2 --- version.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.gradle b/version.gradle index 2c0f24be..957e9e38 100644 --- a/version.gradle +++ b/version.gradle @@ -14,6 +14,6 @@ allprojects { logbackVersion = '1.2.13' mockitoVersion = '4.5.1' slf4jVersion = '1.7.36' - sopJavaVersion = '7.0.1' + sopJavaVersion = '7.0.2' } } From 078c4b84b60242340c2de40f9fd7bd31f7d0a8e7 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Thu, 31 Oct 2024 14:24:04 +0100 Subject: [PATCH 35/40] Update changelog --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f4de3afb..0659df9a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,11 @@ SPDX-License-Identifier: CC0-1.0 # PGPainless Changelog +## 1.6.8-SNAPSHOT +- Bump `sop-java` to `7.0.2` +- SOP `change-key-password`: Fix reading password from indirect parameter instead of erroneously passing filename (fixes #453) +- SOP `revoke-key`: Allow for multiple `--with-key-password` options + ## 1.6.7 - SOP: Fix OOM error when detached-signing large amounts of data (fix #432) - Move `CachingBcPublicKeyDataDecryptorFactory` from `org.bouncycastle` packet to `org.pgpainless.decryption_verification` to avoid package split (partially addresses #428) From 4681d7103918bb2aea162fdcfea68f0778254736 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Thu, 31 Oct 2024 14:30:42 +0100 Subject: [PATCH 36/40] PGPainless 1.6.8 --- CHANGELOG.md | 2 +- README.md | 2 +- pgpainless-sop/README.md | 4 ++-- version.gradle | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0659df9a..6fc3d29a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ SPDX-License-Identifier: CC0-1.0 # PGPainless Changelog -## 1.6.8-SNAPSHOT +## 1.6.8 - Bump `sop-java` to `7.0.2` - SOP `change-key-password`: Fix reading password from indirect parameter instead of erroneously passing filename (fixes #453) - SOP `revoke-key`: Allow for multiple `--with-key-password` options diff --git a/README.md b/README.md index 01eab05d..f3a14377 100644 --- a/README.md +++ b/README.md @@ -191,7 +191,7 @@ repositories { } dependencies { - implementation 'org.pgpainless:pgpainless-core:1.6.7' + implementation 'org.pgpainless:pgpainless-core:1.6.8' } ``` diff --git a/pgpainless-sop/README.md b/pgpainless-sop/README.md index d1e1b246..ba87853f 100644 --- a/pgpainless-sop/README.md +++ b/pgpainless-sop/README.md @@ -23,7 +23,7 @@ To start using pgpainless-sop in your code, include the following lines in your ... dependencies { ... - implementation "org.pgpainless:pgpainless-sop:1.6.7" + implementation "org.pgpainless:pgpainless-sop:1.6.8" ... } @@ -34,7 +34,7 @@ dependencies { org.pgpainless pgpainless-sop - 1.6.7 + 1.6.8 ... diff --git a/version.gradle b/version.gradle index 957e9e38..420e3067 100644 --- a/version.gradle +++ b/version.gradle @@ -5,7 +5,7 @@ allprojects { ext { shortVersion = '1.6.8' - isSnapshot = true + isSnapshot = false pgpainlessMinAndroidSdk = 10 javaSourceCompatibility = 1.8 bouncyCastleVersion = '1.77' From 739070681f652cd2ef60718d0071e7150265d70e Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Thu, 31 Oct 2024 14:32:36 +0100 Subject: [PATCH 37/40] PGPainless 1.6.9-SNAPSHOT --- version.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version.gradle b/version.gradle index 420e3067..8c2e3f0c 100644 --- a/version.gradle +++ b/version.gradle @@ -4,8 +4,8 @@ allprojects { ext { - shortVersion = '1.6.8' - isSnapshot = false + shortVersion = '1.6.9' + isSnapshot = true pgpainlessMinAndroidSdk = 10 javaSourceCompatibility = 1.8 bouncyCastleVersion = '1.77' From 001acb55ee714202de3d4f93e41c7d0c07ea8844 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Fri, 28 Mar 2025 18:28:56 +0100 Subject: [PATCH 38/40] Bump BC to 1.80, apply required code changes We had to rework the HardwareSecurity decryptor factory classes, which now take a PKESK version as additional argument Further, we had to remove support for generating secp256k1 EC keys. Lastly, parsing One-Pass-Signatures of unsupported versions in BC now throws, so we had to introduce a respective catch block. --- pgpainless-core/build.gradle | 1 + ...achingBcPublicKeyDataDecryptorFactory.java | 33 +++++++++++++++---- .../CustomPublicKeyDataDecryptorFactory.java | 5 +-- .../HardwareSecurity.java | 9 ++--- .../OpenPgpMessageInputStream.java | 12 ++++--- .../generation/type/ecc/EllipticCurve.java | 1 - ...stomPublicKeyDataDecryptorFactoryTest.java | 4 +-- version.gradle | 2 +- 8 files changed, 46 insertions(+), 21 deletions(-) diff --git a/pgpainless-core/build.gradle b/pgpainless-core/build.gradle index bab6ecf1..5d251feb 100644 --- a/pgpainless-core/build.gradle +++ b/pgpainless-core/build.gradle @@ -21,6 +21,7 @@ dependencies { // Bouncy Castle api "org.bouncycastle:bcprov-jdk18on:$bouncyCastleVersion" + api "org.bouncycastle:bcutil-jdk18on:$bouncyPgVersion" api "org.bouncycastle:bcpg-jdk18on:$bouncyPgVersion" // api(files("../libs/bcpg-jdk18on-1.70.jar")) diff --git a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/CachingBcPublicKeyDataDecryptorFactory.java b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/CachingBcPublicKeyDataDecryptorFactory.java index 9196cc37..162d1fbb 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/CachingBcPublicKeyDataDecryptorFactory.java +++ b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/CachingBcPublicKeyDataDecryptorFactory.java @@ -4,8 +4,12 @@ package org.pgpainless.decryption_verification; +import org.bouncycastle.bcpg.AEADEncDataPacket; +import org.bouncycastle.bcpg.SymmetricEncIntegrityPacket; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPPrivateKey; +import org.bouncycastle.openpgp.PGPSessionKey; +import org.bouncycastle.openpgp.operator.PGPDataDecryptor; import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory; import org.bouncycastle.openpgp.operator.bc.BcPublicKeyDataDecryptorFactory; import org.bouncycastle.util.encoders.Base64; @@ -27,25 +31,25 @@ import java.util.Map; * The result of that is then placed in the cache and returned. */ public class CachingBcPublicKeyDataDecryptorFactory - extends BcPublicKeyDataDecryptorFactory - implements CustomPublicKeyDataDecryptorFactory { + extends CustomPublicKeyDataDecryptorFactory { private static final Logger LOGGER = LoggerFactory.getLogger(CachingBcPublicKeyDataDecryptorFactory.class); + private final BcPublicKeyDataDecryptorFactory decryptorFactory; private final Map cachedSessionKeys = new HashMap<>(); private final SubkeyIdentifier decryptionKey; public CachingBcPublicKeyDataDecryptorFactory(PGPPrivateKey privateKey, SubkeyIdentifier decryptionKey) { - super(privateKey); + this.decryptorFactory = new BcPublicKeyDataDecryptorFactory(privateKey); this.decryptionKey = decryptionKey; } @Override - public byte[] recoverSessionData(int keyAlgorithm, byte[][] secKeyData) throws PGPException { + public byte[] recoverSessionData(int keyAlgorithm, byte[][] secKeyData, int pkeskVersion) throws PGPException { byte[] sessionKey = lookupSessionKeyData(secKeyData); if (sessionKey == null) { LOGGER.debug("Cache miss for encrypted session key " + Hex.toHexString(secKeyData[0])); - sessionKey = costlyRecoverSessionData(keyAlgorithm, secKeyData); + sessionKey = costlyRecoverSessionData(keyAlgorithm, secKeyData, pkeskVersion); cacheSessionKeyData(secKeyData, sessionKey); } else { LOGGER.debug("Cache hit for encrypted session key " + Hex.toHexString(secKeyData[0])); @@ -53,8 +57,8 @@ public class CachingBcPublicKeyDataDecryptorFactory return sessionKey; } - public byte[] costlyRecoverSessionData(int keyAlgorithm, byte[][] secKeyData) throws PGPException { - return super.recoverSessionData(keyAlgorithm, secKeyData); + public byte[] costlyRecoverSessionData(int keyAlgorithm, byte[][] secKeyData, int pkeskVersion) throws PGPException { + return decryptorFactory.recoverSessionData(keyAlgorithm, secKeyData, pkeskVersion); } private byte[] lookupSessionKeyData(byte[][] secKeyData) { @@ -91,4 +95,19 @@ public class CachingBcPublicKeyDataDecryptorFactory public SubkeyIdentifier getSubkeyIdentifier() { return decryptionKey; } + + @Override + public PGPDataDecryptor createDataDecryptor(boolean b, int i, byte[] bytes) throws PGPException { + return decryptorFactory.createDataDecryptor(b, i, bytes); + } + + @Override + public PGPDataDecryptor createDataDecryptor(AEADEncDataPacket aeadEncDataPacket, PGPSessionKey pgpSessionKey) throws PGPException { + return decryptorFactory.createDataDecryptor(aeadEncDataPacket, pgpSessionKey); + } + + @Override + public PGPDataDecryptor createDataDecryptor(SymmetricEncIntegrityPacket symmetricEncIntegrityPacket, PGPSessionKey pgpSessionKey) throws PGPException { + return decryptorFactory.createDataDecryptor(symmetricEncIntegrityPacket, pgpSessionKey); + } } diff --git a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/CustomPublicKeyDataDecryptorFactory.java b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/CustomPublicKeyDataDecryptorFactory.java index 91902cc7..2b07a059 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/CustomPublicKeyDataDecryptorFactory.java +++ b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/CustomPublicKeyDataDecryptorFactory.java @@ -4,6 +4,7 @@ package org.pgpainless.decryption_verification; +import org.bouncycastle.openpgp.operator.AbstractPublicKeyDataDecryptorFactory; import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory; import org.pgpainless.key.SubkeyIdentifier; @@ -14,7 +15,7 @@ import org.pgpainless.key.SubkeyIdentifier; * TPMs. * @see ConsumerOptions#addCustomDecryptorFactory(CustomPublicKeyDataDecryptorFactory) */ -public interface CustomPublicKeyDataDecryptorFactory extends PublicKeyDataDecryptorFactory { +public abstract class CustomPublicKeyDataDecryptorFactory extends AbstractPublicKeyDataDecryptorFactory { /** * Return the {@link SubkeyIdentifier} for which this particular {@link CustomPublicKeyDataDecryptorFactory} @@ -22,6 +23,6 @@ public interface CustomPublicKeyDataDecryptorFactory extends PublicKeyDataDecryp * * @return subkey identifier */ - SubkeyIdentifier getSubkeyIdentifier(); + abstract SubkeyIdentifier getSubkeyIdentifier(); } diff --git a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/HardwareSecurity.java b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/HardwareSecurity.java index fc88ef33..a8662557 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/HardwareSecurity.java +++ b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/HardwareSecurity.java @@ -29,11 +29,12 @@ public class HardwareSecurity { * @param keyId id of the key * @param keyAlgorithm algorithm * @param sessionKeyData encrypted session key + * @param pkeskVersion Public-Key Encrypted Session-Key Packet version * * @return decrypted session key * @throws HardwareSecurityException exception */ - byte[] decryptSessionKey(long keyId, int keyAlgorithm, byte[] sessionKeyData) + byte[] decryptSessionKey(long keyId, int keyAlgorithm, byte[] sessionKeyData, int pkeskVersion) throws HardwareSecurityException; } @@ -43,7 +44,7 @@ public class HardwareSecurity { * to a {@link DecryptionCallback}. * Users can provide such a callback to delegate decryption of messages to hardware security SDKs. */ - public static class HardwareDataDecryptorFactory implements CustomPublicKeyDataDecryptorFactory { + public static class HardwareDataDecryptorFactory extends CustomPublicKeyDataDecryptorFactory { private final DecryptionCallback callback; // luckily we can instantiate the BcPublicKeyDataDecryptorFactory with null as argument. @@ -63,11 +64,11 @@ public class HardwareSecurity { } @Override - public byte[] recoverSessionData(int keyAlgorithm, byte[][] secKeyData) + public byte[] recoverSessionData(int keyAlgorithm, byte[][] secKeyData, int pkeskVersion) throws PGPException { try { // delegate decryption to the callback - return callback.decryptSessionKey(subkey.getSubkeyId(), keyAlgorithm, secKeyData[0]); + return callback.decryptSessionKey(subkey.getSubkeyId(), keyAlgorithm, secKeyData[0], pkeskVersion); } catch (HardwareSecurityException e) { throw new PGPException("Hardware-backed decryption failed.", e); } diff --git a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/OpenPgpMessageInputStream.java b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/OpenPgpMessageInputStream.java index dd8cf0e2..81465a81 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/OpenPgpMessageInputStream.java +++ b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/OpenPgpMessageInputStream.java @@ -369,10 +369,14 @@ public class OpenPgpMessageInputStream extends DecryptionStream { private void processOnePassSignature() throws PGPException, IOException { 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"); - signatures.addOnePassSignature(onePassSignature); + try { + PGPOnePassSignature onePassSignature = packetInputStream.readOnePassSignature(); + LOGGER.debug("One-Pass-Signature Packet by key " + KeyIdUtil.formatKeyId(onePassSignature.getKeyID()) + + " at depth " + metadata.depth + " encountered"); + signatures.addOnePassSignature(onePassSignature); + } catch (UnsupportedPacketVersionException e) { + LOGGER.debug("Ignoring One-Pass-Signature Packet of unsupported version.", e); + } } private void processSignature() throws PGPException, IOException { diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ecc/EllipticCurve.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ecc/EllipticCurve.java index 2372896e..1ad0e2c6 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ecc/EllipticCurve.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ecc/EllipticCurve.java @@ -18,7 +18,6 @@ public enum EllipticCurve { _P256("prime256v1", 256), // prime256v1 is equivalent to P-256, see https://tools.ietf.org/search/rfc4492#page-32 _P384("secp384r1", 384), // secp384r1 is equivalent to P-384, see https://tools.ietf.org/search/rfc4492#page-32 _P521("secp521r1", 521), // secp521r1 is equivalent to P-521, see https://tools.ietf.org/search/rfc4492#page-32 - _SECP256K1("secp256k1", 256), _BRAINPOOLP256R1("brainpoolP256r1", 256), _BRAINPOOLP384R1("brainpoolP384r1", 384), _BRAINPOOLP512R1("brainpoolP512r1", 512) diff --git a/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/CustomPublicKeyDataDecryptorFactoryTest.java b/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/CustomPublicKeyDataDecryptorFactoryTest.java index 73c3bf56..71fbf9be 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/CustomPublicKeyDataDecryptorFactoryTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/CustomPublicKeyDataDecryptorFactoryTest.java @@ -55,14 +55,14 @@ public class CustomPublicKeyDataDecryptorFactoryTest { HardwareSecurity.DecryptionCallback hardwareDecryptionCallback = new HardwareSecurity.DecryptionCallback() { @Override - public byte[] decryptSessionKey(long keyId, int keyAlgorithm, byte[] sessionKeyData) + public byte[] decryptSessionKey(long keyId, int keyAlgorithm, byte[] sessionKeyData, int pkeskVersion) throws HardwareSecurity.HardwareSecurityException { // Emulate hardware decryption. try { PGPSecretKey decryptionKey = secretKey.getSecretKey(encryptionKey.getKeyID()); PGPPrivateKey privateKey = UnlockSecretKey.unlockSecretKey(decryptionKey, Passphrase.emptyPassphrase()); PublicKeyDataDecryptorFactory internal = new BcPublicKeyDataDecryptorFactory(privateKey); - return internal.recoverSessionData(keyAlgorithm, new byte[][] {sessionKeyData}); + return internal.recoverSessionData(keyAlgorithm, new byte[][] {sessionKeyData}, pkeskVersion); } catch (PGPException e) { throw new HardwareSecurity.HardwareSecurityException(); } diff --git a/version.gradle b/version.gradle index 8c2e3f0c..2bc838a2 100644 --- a/version.gradle +++ b/version.gradle @@ -8,7 +8,7 @@ allprojects { isSnapshot = true pgpainlessMinAndroidSdk = 10 javaSourceCompatibility = 1.8 - bouncyCastleVersion = '1.77' + bouncyCastleVersion = '1.80' bouncyPgVersion = bouncyCastleVersion junitVersion = '5.8.2' logbackVersion = '1.2.13' From 35f55bfd53fc5f14710c84c40c7cec89028e9740 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Fri, 28 Mar 2025 18:31:05 +0100 Subject: [PATCH 39/40] Update CHANGELOG --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6fc3d29a..b3a58155 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,11 @@ SPDX-License-Identifier: CC0-1.0 # PGPainless Changelog +## 1.6.9-SNAPSHOT +- Bump BC to `1.80` + - introduce dependency on `bcutil-jdk18on` + - remove support for generating elliptic curve keys over curve `secp256k1` + ## 1.6.8 - Bump `sop-java` to `7.0.2` - SOP `change-key-password`: Fix reading password from indirect parameter instead of erroneously passing filename (fixes #453) From 3fdc6e0ff47bf0e791d945a6dc8f64e6bd646478 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Fri, 28 Mar 2025 18:40:14 +0100 Subject: [PATCH 40/40] PGPainless 1.6.9 --- CHANGELOG.md | 2 +- README.md | 2 +- pgpainless-sop/README.md | 4 ++-- version.gradle | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3a58155..184a93b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ SPDX-License-Identifier: CC0-1.0 # PGPainless Changelog -## 1.6.9-SNAPSHOT +## 1.6.9 - Bump BC to `1.80` - introduce dependency on `bcutil-jdk18on` - remove support for generating elliptic curve keys over curve `secp256k1` diff --git a/README.md b/README.md index f3a14377..15e0ca4b 100644 --- a/README.md +++ b/README.md @@ -191,7 +191,7 @@ repositories { } dependencies { - implementation 'org.pgpainless:pgpainless-core:1.6.8' + implementation 'org.pgpainless:pgpainless-core:1.6.9' } ``` diff --git a/pgpainless-sop/README.md b/pgpainless-sop/README.md index ba87853f..9b5841b4 100644 --- a/pgpainless-sop/README.md +++ b/pgpainless-sop/README.md @@ -23,7 +23,7 @@ To start using pgpainless-sop in your code, include the following lines in your ... dependencies { ... - implementation "org.pgpainless:pgpainless-sop:1.6.8" + implementation "org.pgpainless:pgpainless-sop:1.6.9" ... } @@ -34,7 +34,7 @@ dependencies { org.pgpainless pgpainless-sop - 1.6.8 + 1.6.9 ... diff --git a/version.gradle b/version.gradle index 2bc838a2..7065fe3c 100644 --- a/version.gradle +++ b/version.gradle @@ -5,7 +5,7 @@ allprojects { ext { shortVersion = '1.6.9' - isSnapshot = true + isSnapshot = false pgpainlessMinAndroidSdk = 10 javaSourceCompatibility = 1.8 bouncyCastleVersion = '1.80'