123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826 |
- /*
- * Copyright (c) 2000-2021 The Legion of the Bouncy Castle Inc. (https://www.bouncycastle.org)
- * <p>
- * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
- * and associated documentation files (the "Software"), to deal in the Software without restriction,
- *including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- * </p>
- * <p>
- * The above copyright notice and this permission notice shall be included in all copies or substantial
- * portions of the Software.
- * </p>
- * <p>
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
- * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
- * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
- * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- * </p>
- */
- package org.eclipse.jgit.gpg.bc.internal.keys;
-
- import java.io.ByteArrayInputStream;
- import java.io.ByteArrayOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.OutputStream;
- import java.math.BigInteger;
- import java.util.Date;
-
- import org.bouncycastle.asn1.x9.ECNamedCurveTable;
- import org.bouncycastle.bcpg.DSAPublicBCPGKey;
- import org.bouncycastle.bcpg.DSASecretBCPGKey;
- import org.bouncycastle.bcpg.ECDSAPublicBCPGKey;
- import org.bouncycastle.bcpg.ECPublicBCPGKey;
- import org.bouncycastle.bcpg.ECSecretBCPGKey;
- import org.bouncycastle.bcpg.ElGamalPublicBCPGKey;
- import org.bouncycastle.bcpg.ElGamalSecretBCPGKey;
- import org.bouncycastle.bcpg.HashAlgorithmTags;
- import org.bouncycastle.bcpg.PublicKeyAlgorithmTags;
- import org.bouncycastle.bcpg.PublicKeyPacket;
- import org.bouncycastle.bcpg.RSAPublicBCPGKey;
- import org.bouncycastle.bcpg.RSASecretBCPGKey;
- import org.bouncycastle.bcpg.S2K;
- import org.bouncycastle.bcpg.SecretKeyPacket;
- import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
- import org.bouncycastle.openpgp.PGPException;
- import org.bouncycastle.openpgp.PGPPublicKey;
- import org.bouncycastle.openpgp.PGPSecretKey;
- import org.bouncycastle.openpgp.operator.KeyFingerPrintCalculator;
- import org.bouncycastle.openpgp.operator.PBEProtectionRemoverFactory;
- import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor;
- import org.bouncycastle.openpgp.operator.PGPDigestCalculator;
- import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider;
- import org.bouncycastle.util.Arrays;
- import org.bouncycastle.util.Strings;
-
- /**
- * A parser for secret keys stored in s-expressions. Original BouncyCastle code
- * modified by the JGit team to:
- * <ul>
- * <li>handle unencrypted DSA, EC, and ElGamal keys (upstream only handles
- * unencrypted RSA), and</li>
- * <li>handle secret keys using AES/OCB as encryption (those don't have a
- * hash).</li>
- * </ul>
- */
- @SuppressWarnings("nls")
- public class SExprParser {
- private final PGPDigestCalculatorProvider digestProvider;
-
- /**
- * Base constructor.
- *
- * @param digestProvider
- * a provider for digest calculations. Used to confirm key
- * protection hashes.
- */
- public SExprParser(PGPDigestCalculatorProvider digestProvider) {
- this.digestProvider = digestProvider;
- }
-
- /**
- * Parse a secret key from one of the GPG S expression keys associating it
- * with the passed in public key.
- *
- * @param inputStream
- * to read from
- * @param keyProtectionRemoverFactory
- * for decrypting encrypted keys
- * @param pubKey
- * the private key should belong to
- *
- * @return a secret key object.
- * @throws IOException
- * @throws PGPException
- */
- public PGPSecretKey parseSecretKey(InputStream inputStream,
- PBEProtectionRemoverFactory keyProtectionRemoverFactory,
- PGPPublicKey pubKey) throws IOException, PGPException {
- SXprUtils.skipOpenParenthesis(inputStream);
-
- String type;
-
- type = SXprUtils.readString(inputStream, inputStream.read());
- if (type.equals("protected-private-key")
- || type.equals("private-key")) {
- SXprUtils.skipOpenParenthesis(inputStream);
-
- String keyType = SXprUtils.readString(inputStream,
- inputStream.read());
- if (keyType.equals("ecc")) {
- SXprUtils.skipOpenParenthesis(inputStream);
-
- String curveID = SXprUtils.readString(inputStream,
- inputStream.read());
- String curveName = SXprUtils.readString(inputStream,
- inputStream.read());
-
- SXprUtils.skipCloseParenthesis(inputStream);
-
- byte[] qVal;
-
- SXprUtils.skipOpenParenthesis(inputStream);
-
- type = SXprUtils.readString(inputStream, inputStream.read());
- if (type.equals("q")) {
- qVal = SXprUtils.readBytes(inputStream, inputStream.read());
- } else {
- throw new PGPException("no q value found");
- }
-
- SXprUtils.skipCloseParenthesis(inputStream);
-
- BigInteger d = processECSecretKey(inputStream, curveID,
- curveName, qVal, keyProtectionRemoverFactory);
-
- if (curveName.startsWith("NIST ")) {
- curveName = curveName.substring("NIST ".length());
- }
-
- ECPublicBCPGKey basePubKey = new ECDSAPublicBCPGKey(
- ECNamedCurveTable.getOID(curveName),
- new BigInteger(1, qVal));
- ECPublicBCPGKey assocPubKey = (ECPublicBCPGKey) pubKey
- .getPublicKeyPacket().getKey();
- if (!basePubKey.getCurveOID().equals(assocPubKey.getCurveOID())
- || !basePubKey.getEncodedPoint()
- .equals(assocPubKey.getEncodedPoint())) {
- throw new PGPException(
- "passed in public key does not match secret key");
- }
-
- return new PGPSecretKey(
- new SecretKeyPacket(pubKey.getPublicKeyPacket(),
- SymmetricKeyAlgorithmTags.NULL, null, null,
- new ECSecretBCPGKey(d).getEncoded()),
- pubKey);
- } else if (keyType.equals("dsa")) {
- BigInteger p = readBigInteger("p", inputStream);
- BigInteger q = readBigInteger("q", inputStream);
- BigInteger g = readBigInteger("g", inputStream);
-
- BigInteger y = readBigInteger("y", inputStream);
-
- BigInteger x = processDSASecretKey(inputStream, p, q, g, y,
- keyProtectionRemoverFactory);
-
- DSAPublicBCPGKey basePubKey = new DSAPublicBCPGKey(p, q, g, y);
- DSAPublicBCPGKey assocPubKey = (DSAPublicBCPGKey) pubKey
- .getPublicKeyPacket().getKey();
- if (!basePubKey.getP().equals(assocPubKey.getP())
- || !basePubKey.getQ().equals(assocPubKey.getQ())
- || !basePubKey.getG().equals(assocPubKey.getG())
- || !basePubKey.getY().equals(assocPubKey.getY())) {
- throw new PGPException(
- "passed in public key does not match secret key");
- }
- return new PGPSecretKey(
- new SecretKeyPacket(pubKey.getPublicKeyPacket(),
- SymmetricKeyAlgorithmTags.NULL, null, null,
- new DSASecretBCPGKey(x).getEncoded()),
- pubKey);
- } else if (keyType.equals("elg")) {
- BigInteger p = readBigInteger("p", inputStream);
- BigInteger g = readBigInteger("g", inputStream);
-
- BigInteger y = readBigInteger("y", inputStream);
-
- BigInteger x = processElGamalSecretKey(inputStream, p, g, y,
- keyProtectionRemoverFactory);
-
- ElGamalPublicBCPGKey basePubKey = new ElGamalPublicBCPGKey(p, g,
- y);
- ElGamalPublicBCPGKey assocPubKey = (ElGamalPublicBCPGKey) pubKey
- .getPublicKeyPacket().getKey();
- if (!basePubKey.getP().equals(assocPubKey.getP())
- || !basePubKey.getG().equals(assocPubKey.getG())
- || !basePubKey.getY().equals(assocPubKey.getY())) {
- throw new PGPException(
- "passed in public key does not match secret key");
- }
-
- return new PGPSecretKey(
- new SecretKeyPacket(pubKey.getPublicKeyPacket(),
- SymmetricKeyAlgorithmTags.NULL, null, null,
- new ElGamalSecretBCPGKey(x).getEncoded()),
- pubKey);
- } else if (keyType.equals("rsa")) {
- BigInteger n = readBigInteger("n", inputStream);
- BigInteger e = readBigInteger("e", inputStream);
-
- BigInteger[] values = processRSASecretKey(inputStream, n, e,
- keyProtectionRemoverFactory);
-
- // TODO: type of RSA key?
- RSAPublicBCPGKey basePubKey = new RSAPublicBCPGKey(n, e);
- RSAPublicBCPGKey assocPubKey = (RSAPublicBCPGKey) pubKey
- .getPublicKeyPacket().getKey();
- if (!basePubKey.getModulus().equals(assocPubKey.getModulus())
- || !basePubKey.getPublicExponent()
- .equals(assocPubKey.getPublicExponent())) {
- throw new PGPException(
- "passed in public key does not match secret key");
- }
-
- return new PGPSecretKey(new SecretKeyPacket(
- pubKey.getPublicKeyPacket(),
- SymmetricKeyAlgorithmTags.NULL, null, null,
- new RSASecretBCPGKey(values[0], values[1], values[2])
- .getEncoded()),
- pubKey);
- } else {
- throw new PGPException("unknown key type: " + keyType);
- }
- }
-
- throw new PGPException("unknown key type found");
- }
-
- /**
- * Parse a secret key from one of the GPG S expression keys.
- *
- * @param inputStream
- * to read from
- * @param keyProtectionRemoverFactory
- * for decrypting encrypted keys
- * @param fingerPrintCalculator
- * for calculating key fingerprints
- *
- * @return a secret key object.
- * @throws IOException
- * @throws PGPException
- */
- public PGPSecretKey parseSecretKey(InputStream inputStream,
- PBEProtectionRemoverFactory keyProtectionRemoverFactory,
- KeyFingerPrintCalculator fingerPrintCalculator)
- throws IOException, PGPException {
- SXprUtils.skipOpenParenthesis(inputStream);
-
- String type;
-
- type = SXprUtils.readString(inputStream, inputStream.read());
- if (type.equals("protected-private-key")
- || type.equals("private-key")) {
- SXprUtils.skipOpenParenthesis(inputStream);
-
- String keyType = SXprUtils.readString(inputStream,
- inputStream.read());
- if (keyType.equals("ecc")) {
- SXprUtils.skipOpenParenthesis(inputStream);
-
- String curveID = SXprUtils.readString(inputStream,
- inputStream.read());
- String curveName = SXprUtils.readString(inputStream,
- inputStream.read());
-
- if (curveName.startsWith("NIST ")) {
- curveName = curveName.substring("NIST ".length());
- }
-
- SXprUtils.skipCloseParenthesis(inputStream);
-
- byte[] qVal;
-
- SXprUtils.skipOpenParenthesis(inputStream);
-
- type = SXprUtils.readString(inputStream, inputStream.read());
- if (type.equals("q")) {
- qVal = SXprUtils.readBytes(inputStream, inputStream.read());
- } else {
- throw new PGPException("no q value found");
- }
-
- PublicKeyPacket pubPacket = new PublicKeyPacket(
- PublicKeyAlgorithmTags.ECDSA, new Date(),
- new ECDSAPublicBCPGKey(
- ECNamedCurveTable.getOID(curveName),
- new BigInteger(1, qVal)));
-
- SXprUtils.skipCloseParenthesis(inputStream);
-
- BigInteger d = processECSecretKey(inputStream, curveID,
- curveName, qVal, keyProtectionRemoverFactory);
-
- return new PGPSecretKey(
- new SecretKeyPacket(pubPacket,
- SymmetricKeyAlgorithmTags.NULL, null, null,
- new ECSecretBCPGKey(d).getEncoded()),
- new PGPPublicKey(pubPacket, fingerPrintCalculator));
- } else if (keyType.equals("dsa")) {
- BigInteger p = readBigInteger("p", inputStream);
- BigInteger q = readBigInteger("q", inputStream);
- BigInteger g = readBigInteger("g", inputStream);
-
- BigInteger y = readBigInteger("y", inputStream);
-
- BigInteger x = processDSASecretKey(inputStream, p, q, g, y,
- keyProtectionRemoverFactory);
-
- PublicKeyPacket pubPacket = new PublicKeyPacket(
- PublicKeyAlgorithmTags.DSA, new Date(),
- new DSAPublicBCPGKey(p, q, g, y));
-
- return new PGPSecretKey(
- new SecretKeyPacket(pubPacket,
- SymmetricKeyAlgorithmTags.NULL, null, null,
- new DSASecretBCPGKey(x).getEncoded()),
- new PGPPublicKey(pubPacket, fingerPrintCalculator));
- } else if (keyType.equals("elg")) {
- BigInteger p = readBigInteger("p", inputStream);
- BigInteger g = readBigInteger("g", inputStream);
-
- BigInteger y = readBigInteger("y", inputStream);
-
- BigInteger x = processElGamalSecretKey(inputStream, p, g, y,
- keyProtectionRemoverFactory);
-
- PublicKeyPacket pubPacket = new PublicKeyPacket(
- PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT, new Date(),
- new ElGamalPublicBCPGKey(p, g, y));
-
- return new PGPSecretKey(
- new SecretKeyPacket(pubPacket,
- SymmetricKeyAlgorithmTags.NULL, null, null,
- new ElGamalSecretBCPGKey(x).getEncoded()),
- new PGPPublicKey(pubPacket, fingerPrintCalculator));
- } else if (keyType.equals("rsa")) {
- BigInteger n = readBigInteger("n", inputStream);
- BigInteger e = readBigInteger("e", inputStream);
-
- BigInteger[] values = processRSASecretKey(inputStream, n, e,
- keyProtectionRemoverFactory);
-
- // TODO: type of RSA key?
- PublicKeyPacket pubPacket = new PublicKeyPacket(
- PublicKeyAlgorithmTags.RSA_GENERAL, new Date(),
- new RSAPublicBCPGKey(n, e));
-
- return new PGPSecretKey(
- new SecretKeyPacket(pubPacket,
- SymmetricKeyAlgorithmTags.NULL, null, null,
- new RSASecretBCPGKey(values[0], values[1],
- values[2]).getEncoded()),
- new PGPPublicKey(pubPacket, fingerPrintCalculator));
- } else {
- throw new PGPException("unknown key type: " + keyType);
- }
- }
-
- throw new PGPException("unknown key type found");
- }
-
- private BigInteger readBigInteger(String expectedType,
- InputStream inputStream) throws IOException, PGPException {
- SXprUtils.skipOpenParenthesis(inputStream);
-
- String type = SXprUtils.readString(inputStream, inputStream.read());
- if (!type.equals(expectedType)) {
- throw new PGPException(expectedType + " value expected");
- }
-
- byte[] nBytes = SXprUtils.readBytes(inputStream, inputStream.read());
- BigInteger v = new BigInteger(1, nBytes);
-
- SXprUtils.skipCloseParenthesis(inputStream);
-
- return v;
- }
-
- private static byte[][] extractData(InputStream inputStream,
- PBEProtectionRemoverFactory keyProtectionRemoverFactory)
- throws PGPException, IOException {
- byte[] data;
- byte[] protectedAt = null;
-
- SXprUtils.skipOpenParenthesis(inputStream);
-
- String type = SXprUtils.readString(inputStream, inputStream.read());
- if (type.equals("protected")) {
- String protection = SXprUtils.readString(inputStream,
- inputStream.read());
-
- SXprUtils.skipOpenParenthesis(inputStream);
-
- S2K s2k = SXprUtils.parseS2K(inputStream);
-
- byte[] iv = SXprUtils.readBytes(inputStream, inputStream.read());
-
- SXprUtils.skipCloseParenthesis(inputStream);
-
- byte[] secKeyData = SXprUtils.readBytes(inputStream,
- inputStream.read());
-
- SXprUtils.skipCloseParenthesis(inputStream);
-
- PBESecretKeyDecryptor keyDecryptor = keyProtectionRemoverFactory
- .createDecryptor(protection);
-
- // TODO: recognise other algorithms
- byte[] key = keyDecryptor.makeKeyFromPassPhrase(
- SymmetricKeyAlgorithmTags.AES_128, s2k);
-
- data = keyDecryptor.recoverKeyData(
- SymmetricKeyAlgorithmTags.AES_128, key, iv, secKeyData, 0,
- secKeyData.length);
-
- // check if protected at is present
- if (inputStream.read() == '(') {
- ByteArrayOutputStream bOut = new ByteArrayOutputStream();
-
- bOut.write('(');
- int ch;
- while ((ch = inputStream.read()) >= 0 && ch != ')') {
- bOut.write(ch);
- }
-
- if (ch != ')') {
- throw new IOException("unexpected end to SExpr");
- }
-
- bOut.write(')');
-
- protectedAt = bOut.toByteArray();
- }
-
- SXprUtils.skipCloseParenthesis(inputStream);
- SXprUtils.skipCloseParenthesis(inputStream);
- } else if (type.equals("d") || type.equals("x")) {
- // JGit modification: unencrypted DSA or ECC keys can have an "x"
- // here
- return null;
- } else {
- throw new PGPException("protected block not found");
- }
-
- return new byte[][] { data, protectedAt };
- }
-
- private BigInteger processDSASecretKey(InputStream inputStream,
- BigInteger p, BigInteger q, BigInteger g, BigInteger y,
- PBEProtectionRemoverFactory keyProtectionRemoverFactory)
- throws IOException, PGPException {
- String type;
- byte[][] basicData = extractData(inputStream,
- keyProtectionRemoverFactory);
-
- // JGit modification: handle unencrypted DSA keys
- if (basicData == null) {
- byte[] nBytes = SXprUtils.readBytes(inputStream,
- inputStream.read());
- BigInteger x = new BigInteger(1, nBytes);
- SXprUtils.skipCloseParenthesis(inputStream);
- return x;
- }
-
- byte[] keyData = basicData[0];
- byte[] protectedAt = basicData[1];
-
- //
- // parse the secret key S-expr
- //
- InputStream keyIn = new ByteArrayInputStream(keyData);
-
- SXprUtils.skipOpenParenthesis(keyIn);
- SXprUtils.skipOpenParenthesis(keyIn);
-
- BigInteger x = readBigInteger("x", keyIn);
-
- SXprUtils.skipCloseParenthesis(keyIn);
-
- // JGit modification: OCB-encrypted keys don't have and don't need a
- // hash
- if (keyProtectionRemoverFactory instanceof OCBPBEProtectionRemoverFactory) {
- return x;
- }
-
- SXprUtils.skipOpenParenthesis(keyIn);
- type = SXprUtils.readString(keyIn, keyIn.read());
-
- if (!type.equals("hash")) {
- throw new PGPException("hash keyword expected");
- }
- type = SXprUtils.readString(keyIn, keyIn.read());
-
- if (!type.equals("sha1")) {
- throw new PGPException("hash keyword expected");
- }
-
- byte[] hashBytes = SXprUtils.readBytes(keyIn, keyIn.read());
-
- SXprUtils.skipCloseParenthesis(keyIn);
-
- if (digestProvider != null) {
- PGPDigestCalculator digestCalculator = digestProvider
- .get(HashAlgorithmTags.SHA1);
-
- OutputStream dOut = digestCalculator.getOutputStream();
-
- dOut.write(Strings.toByteArray("(3:dsa"));
- writeCanonical(dOut, "p", p);
- writeCanonical(dOut, "q", q);
- writeCanonical(dOut, "g", g);
- writeCanonical(dOut, "y", y);
- writeCanonical(dOut, "x", x);
-
- // check protected-at
- if (protectedAt != null) {
- dOut.write(protectedAt);
- }
-
- dOut.write(Strings.toByteArray(")"));
-
- byte[] check = digestCalculator.getDigest();
- if (!Arrays.constantTimeAreEqual(check, hashBytes)) {
- throw new PGPException(
- "checksum on protected data failed in SExpr");
- }
- }
-
- return x;
- }
-
- private BigInteger processElGamalSecretKey(InputStream inputStream,
- BigInteger p, BigInteger g, BigInteger y,
- PBEProtectionRemoverFactory keyProtectionRemoverFactory)
- throws IOException, PGPException {
- String type;
- byte[][] basicData = extractData(inputStream,
- keyProtectionRemoverFactory);
-
- // JGit modification: handle unencrypted EC keys
- if (basicData == null) {
- byte[] nBytes = SXprUtils.readBytes(inputStream,
- inputStream.read());
- BigInteger x = new BigInteger(1, nBytes);
- SXprUtils.skipCloseParenthesis(inputStream);
- return x;
- }
-
- byte[] keyData = basicData[0];
- byte[] protectedAt = basicData[1];
-
- //
- // parse the secret key S-expr
- //
- InputStream keyIn = new ByteArrayInputStream(keyData);
-
- SXprUtils.skipOpenParenthesis(keyIn);
- SXprUtils.skipOpenParenthesis(keyIn);
-
- BigInteger x = readBigInteger("x", keyIn);
-
- SXprUtils.skipCloseParenthesis(keyIn);
-
- // JGit modification: OCB-encrypted keys don't have and don't need a
- // hash
- if (keyProtectionRemoverFactory instanceof OCBPBEProtectionRemoverFactory) {
- return x;
- }
-
- SXprUtils.skipOpenParenthesis(keyIn);
- type = SXprUtils.readString(keyIn, keyIn.read());
-
- if (!type.equals("hash")) {
- throw new PGPException("hash keyword expected");
- }
- type = SXprUtils.readString(keyIn, keyIn.read());
-
- if (!type.equals("sha1")) {
- throw new PGPException("hash keyword expected");
- }
-
- byte[] hashBytes = SXprUtils.readBytes(keyIn, keyIn.read());
-
- SXprUtils.skipCloseParenthesis(keyIn);
-
- if (digestProvider != null) {
- PGPDigestCalculator digestCalculator = digestProvider
- .get(HashAlgorithmTags.SHA1);
-
- OutputStream dOut = digestCalculator.getOutputStream();
-
- dOut.write(Strings.toByteArray("(3:elg"));
- writeCanonical(dOut, "p", p);
- writeCanonical(dOut, "g", g);
- writeCanonical(dOut, "y", y);
- writeCanonical(dOut, "x", x);
-
- // check protected-at
- if (protectedAt != null) {
- dOut.write(protectedAt);
- }
-
- dOut.write(Strings.toByteArray(")"));
-
- byte[] check = digestCalculator.getDigest();
- if (!Arrays.constantTimeAreEqual(check, hashBytes)) {
- throw new PGPException(
- "checksum on protected data failed in SExpr");
- }
- }
-
- return x;
- }
-
- private BigInteger processECSecretKey(InputStream inputStream,
- String curveID, String curveName, byte[] qVal,
- PBEProtectionRemoverFactory keyProtectionRemoverFactory)
- throws IOException, PGPException {
- String type;
-
- byte[][] basicData = extractData(inputStream,
- keyProtectionRemoverFactory);
-
- // JGit modification: handle unencrypted EC keys
- if (basicData == null) {
- byte[] nBytes = SXprUtils.readBytes(inputStream,
- inputStream.read());
- BigInteger d = new BigInteger(1, nBytes);
- SXprUtils.skipCloseParenthesis(inputStream);
- return d;
- }
-
- byte[] keyData = basicData[0];
- byte[] protectedAt = basicData[1];
-
- //
- // parse the secret key S-expr
- //
- InputStream keyIn = new ByteArrayInputStream(keyData);
-
- SXprUtils.skipOpenParenthesis(keyIn);
- SXprUtils.skipOpenParenthesis(keyIn);
- BigInteger d = readBigInteger("d", keyIn);
- SXprUtils.skipCloseParenthesis(keyIn);
-
- // JGit modification: OCB-encrypted keys don't have and don't need a
- // hash
- if (keyProtectionRemoverFactory instanceof OCBPBEProtectionRemoverFactory) {
- return d;
- }
-
- SXprUtils.skipOpenParenthesis(keyIn);
-
- type = SXprUtils.readString(keyIn, keyIn.read());
-
- if (!type.equals("hash")) {
- throw new PGPException("hash keyword expected");
- }
- type = SXprUtils.readString(keyIn, keyIn.read());
-
- if (!type.equals("sha1")) {
- throw new PGPException("hash keyword expected");
- }
-
- byte[] hashBytes = SXprUtils.readBytes(keyIn, keyIn.read());
-
- SXprUtils.skipCloseParenthesis(keyIn);
-
- if (digestProvider != null) {
- PGPDigestCalculator digestCalculator = digestProvider
- .get(HashAlgorithmTags.SHA1);
-
- OutputStream dOut = digestCalculator.getOutputStream();
-
- dOut.write(Strings.toByteArray("(3:ecc"));
-
- dOut.write(Strings.toByteArray("(" + curveID.length() + ":"
- + curveID + curveName.length() + ":" + curveName + ")"));
-
- writeCanonical(dOut, "q", qVal);
- writeCanonical(dOut, "d", d);
-
- // check protected-at
- if (protectedAt != null) {
- dOut.write(protectedAt);
- }
-
- dOut.write(Strings.toByteArray(")"));
-
- byte[] check = digestCalculator.getDigest();
-
- if (!Arrays.constantTimeAreEqual(check, hashBytes)) {
- throw new PGPException(
- "checksum on protected data failed in SExpr");
- }
- }
-
- return d;
- }
-
- private BigInteger[] processRSASecretKey(InputStream inputStream,
- BigInteger n, BigInteger e,
- PBEProtectionRemoverFactory keyProtectionRemoverFactory)
- throws IOException, PGPException {
- String type;
- byte[][] basicData = extractData(inputStream,
- keyProtectionRemoverFactory);
-
- byte[] keyData;
- byte[] protectedAt = null;
-
- InputStream keyIn;
- BigInteger d;
-
- if (basicData == null) {
- keyIn = inputStream;
- byte[] nBytes = SXprUtils.readBytes(inputStream,
- inputStream.read());
- d = new BigInteger(1, nBytes);
-
- SXprUtils.skipCloseParenthesis(inputStream);
-
- } else {
- keyData = basicData[0];
- protectedAt = basicData[1];
-
- keyIn = new ByteArrayInputStream(keyData);
-
- SXprUtils.skipOpenParenthesis(keyIn);
- SXprUtils.skipOpenParenthesis(keyIn);
- d = readBigInteger("d", keyIn);
- }
-
- //
- // parse the secret key S-expr
- //
-
- BigInteger p = readBigInteger("p", keyIn);
- BigInteger q = readBigInteger("q", keyIn);
- BigInteger u = readBigInteger("u", keyIn);
-
- // JGit modification: OCB-encrypted keys don't have and don't need a
- // hash
- if (basicData == null
- || keyProtectionRemoverFactory instanceof OCBPBEProtectionRemoverFactory) {
- return new BigInteger[] { d, p, q, u };
- }
-
- SXprUtils.skipCloseParenthesis(keyIn);
-
- SXprUtils.skipOpenParenthesis(keyIn);
- type = SXprUtils.readString(keyIn, keyIn.read());
-
- if (!type.equals("hash")) {
- throw new PGPException("hash keyword expected");
- }
- type = SXprUtils.readString(keyIn, keyIn.read());
-
- if (!type.equals("sha1")) {
- throw new PGPException("hash keyword expected");
- }
-
- byte[] hashBytes = SXprUtils.readBytes(keyIn, keyIn.read());
-
- SXprUtils.skipCloseParenthesis(keyIn);
-
- if (digestProvider != null) {
- PGPDigestCalculator digestCalculator = digestProvider
- .get(HashAlgorithmTags.SHA1);
-
- OutputStream dOut = digestCalculator.getOutputStream();
-
- dOut.write(Strings.toByteArray("(3:rsa"));
-
- writeCanonical(dOut, "n", n);
- writeCanonical(dOut, "e", e);
- writeCanonical(dOut, "d", d);
- writeCanonical(dOut, "p", p);
- writeCanonical(dOut, "q", q);
- writeCanonical(dOut, "u", u);
-
- // check protected-at
- if (protectedAt != null) {
- dOut.write(protectedAt);
- }
-
- dOut.write(Strings.toByteArray(")"));
-
- byte[] check = digestCalculator.getDigest();
-
- if (!Arrays.constantTimeAreEqual(check, hashBytes)) {
- throw new PGPException(
- "checksum on protected data failed in SExpr");
- }
- }
-
- return new BigInteger[] { d, p, q, u };
- }
-
- private void writeCanonical(OutputStream dOut, String label, BigInteger i)
- throws IOException {
- writeCanonical(dOut, label, i.toByteArray());
- }
-
- private void writeCanonical(OutputStream dOut, String label, byte[] data)
- throws IOException {
- dOut.write(Strings.toByteArray(
- "(" + label.length() + ":" + label + data.length + ":"));
- dOut.write(data);
- dOut.write(Strings.toByteArray(")"));
- }
- }
|