You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

SExprParser.java 25KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826
  1. /*
  2. * Copyright (c) 2000-2021 The Legion of the Bouncy Castle Inc. (https://www.bouncycastle.org)
  3. * <p>
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
  5. * and associated documentation files (the "Software"), to deal in the Software without restriction,
  6. *including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
  7. * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
  8. * subject to the following conditions:
  9. * </p>
  10. * <p>
  11. * The above copyright notice and this permission notice shall be included in all copies or substantial
  12. * portions of the Software.
  13. * </p>
  14. * <p>
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  16. * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  17. * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  18. * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  19. * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  20. * DEALINGS IN THE SOFTWARE.
  21. * </p>
  22. */
  23. package org.eclipse.jgit.gpg.bc.internal.keys;
  24. import java.io.ByteArrayInputStream;
  25. import java.io.ByteArrayOutputStream;
  26. import java.io.IOException;
  27. import java.io.InputStream;
  28. import java.io.OutputStream;
  29. import java.math.BigInteger;
  30. import java.util.Date;
  31. import org.bouncycastle.asn1.x9.ECNamedCurveTable;
  32. import org.bouncycastle.bcpg.DSAPublicBCPGKey;
  33. import org.bouncycastle.bcpg.DSASecretBCPGKey;
  34. import org.bouncycastle.bcpg.ECDSAPublicBCPGKey;
  35. import org.bouncycastle.bcpg.ECPublicBCPGKey;
  36. import org.bouncycastle.bcpg.ECSecretBCPGKey;
  37. import org.bouncycastle.bcpg.ElGamalPublicBCPGKey;
  38. import org.bouncycastle.bcpg.ElGamalSecretBCPGKey;
  39. import org.bouncycastle.bcpg.HashAlgorithmTags;
  40. import org.bouncycastle.bcpg.PublicKeyAlgorithmTags;
  41. import org.bouncycastle.bcpg.PublicKeyPacket;
  42. import org.bouncycastle.bcpg.RSAPublicBCPGKey;
  43. import org.bouncycastle.bcpg.RSASecretBCPGKey;
  44. import org.bouncycastle.bcpg.S2K;
  45. import org.bouncycastle.bcpg.SecretKeyPacket;
  46. import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
  47. import org.bouncycastle.openpgp.PGPException;
  48. import org.bouncycastle.openpgp.PGPPublicKey;
  49. import org.bouncycastle.openpgp.PGPSecretKey;
  50. import org.bouncycastle.openpgp.operator.KeyFingerPrintCalculator;
  51. import org.bouncycastle.openpgp.operator.PBEProtectionRemoverFactory;
  52. import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor;
  53. import org.bouncycastle.openpgp.operator.PGPDigestCalculator;
  54. import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider;
  55. import org.bouncycastle.util.Arrays;
  56. import org.bouncycastle.util.Strings;
  57. /**
  58. * A parser for secret keys stored in s-expressions. Original BouncyCastle code
  59. * modified by the JGit team to:
  60. * <ul>
  61. * <li>handle unencrypted DSA, EC, and ElGamal keys (upstream only handles
  62. * unencrypted RSA), and</li>
  63. * <li>handle secret keys using AES/OCB as encryption (those don't have a
  64. * hash).</li>
  65. * </ul>
  66. */
  67. @SuppressWarnings("nls")
  68. public class SExprParser {
  69. private final PGPDigestCalculatorProvider digestProvider;
  70. /**
  71. * Base constructor.
  72. *
  73. * @param digestProvider
  74. * a provider for digest calculations. Used to confirm key
  75. * protection hashes.
  76. */
  77. public SExprParser(PGPDigestCalculatorProvider digestProvider) {
  78. this.digestProvider = digestProvider;
  79. }
  80. /**
  81. * Parse a secret key from one of the GPG S expression keys associating it
  82. * with the passed in public key.
  83. *
  84. * @param inputStream
  85. * to read from
  86. * @param keyProtectionRemoverFactory
  87. * for decrypting encrypted keys
  88. * @param pubKey
  89. * the private key should belong to
  90. *
  91. * @return a secret key object.
  92. * @throws IOException
  93. * @throws PGPException
  94. */
  95. public PGPSecretKey parseSecretKey(InputStream inputStream,
  96. PBEProtectionRemoverFactory keyProtectionRemoverFactory,
  97. PGPPublicKey pubKey) throws IOException, PGPException {
  98. SXprUtils.skipOpenParenthesis(inputStream);
  99. String type;
  100. type = SXprUtils.readString(inputStream, inputStream.read());
  101. if (type.equals("protected-private-key")
  102. || type.equals("private-key")) {
  103. SXprUtils.skipOpenParenthesis(inputStream);
  104. String keyType = SXprUtils.readString(inputStream,
  105. inputStream.read());
  106. if (keyType.equals("ecc")) {
  107. SXprUtils.skipOpenParenthesis(inputStream);
  108. String curveID = SXprUtils.readString(inputStream,
  109. inputStream.read());
  110. String curveName = SXprUtils.readString(inputStream,
  111. inputStream.read());
  112. SXprUtils.skipCloseParenthesis(inputStream);
  113. byte[] qVal;
  114. SXprUtils.skipOpenParenthesis(inputStream);
  115. type = SXprUtils.readString(inputStream, inputStream.read());
  116. if (type.equals("q")) {
  117. qVal = SXprUtils.readBytes(inputStream, inputStream.read());
  118. } else {
  119. throw new PGPException("no q value found");
  120. }
  121. SXprUtils.skipCloseParenthesis(inputStream);
  122. BigInteger d = processECSecretKey(inputStream, curveID,
  123. curveName, qVal, keyProtectionRemoverFactory);
  124. if (curveName.startsWith("NIST ")) {
  125. curveName = curveName.substring("NIST ".length());
  126. }
  127. ECPublicBCPGKey basePubKey = new ECDSAPublicBCPGKey(
  128. ECNamedCurveTable.getOID(curveName),
  129. new BigInteger(1, qVal));
  130. ECPublicBCPGKey assocPubKey = (ECPublicBCPGKey) pubKey
  131. .getPublicKeyPacket().getKey();
  132. if (!basePubKey.getCurveOID().equals(assocPubKey.getCurveOID())
  133. || !basePubKey.getEncodedPoint()
  134. .equals(assocPubKey.getEncodedPoint())) {
  135. throw new PGPException(
  136. "passed in public key does not match secret key");
  137. }
  138. return new PGPSecretKey(
  139. new SecretKeyPacket(pubKey.getPublicKeyPacket(),
  140. SymmetricKeyAlgorithmTags.NULL, null, null,
  141. new ECSecretBCPGKey(d).getEncoded()),
  142. pubKey);
  143. } else if (keyType.equals("dsa")) {
  144. BigInteger p = readBigInteger("p", inputStream);
  145. BigInteger q = readBigInteger("q", inputStream);
  146. BigInteger g = readBigInteger("g", inputStream);
  147. BigInteger y = readBigInteger("y", inputStream);
  148. BigInteger x = processDSASecretKey(inputStream, p, q, g, y,
  149. keyProtectionRemoverFactory);
  150. DSAPublicBCPGKey basePubKey = new DSAPublicBCPGKey(p, q, g, y);
  151. DSAPublicBCPGKey assocPubKey = (DSAPublicBCPGKey) pubKey
  152. .getPublicKeyPacket().getKey();
  153. if (!basePubKey.getP().equals(assocPubKey.getP())
  154. || !basePubKey.getQ().equals(assocPubKey.getQ())
  155. || !basePubKey.getG().equals(assocPubKey.getG())
  156. || !basePubKey.getY().equals(assocPubKey.getY())) {
  157. throw new PGPException(
  158. "passed in public key does not match secret key");
  159. }
  160. return new PGPSecretKey(
  161. new SecretKeyPacket(pubKey.getPublicKeyPacket(),
  162. SymmetricKeyAlgorithmTags.NULL, null, null,
  163. new DSASecretBCPGKey(x).getEncoded()),
  164. pubKey);
  165. } else if (keyType.equals("elg")) {
  166. BigInteger p = readBigInteger("p", inputStream);
  167. BigInteger g = readBigInteger("g", inputStream);
  168. BigInteger y = readBigInteger("y", inputStream);
  169. BigInteger x = processElGamalSecretKey(inputStream, p, g, y,
  170. keyProtectionRemoverFactory);
  171. ElGamalPublicBCPGKey basePubKey = new ElGamalPublicBCPGKey(p, g,
  172. y);
  173. ElGamalPublicBCPGKey assocPubKey = (ElGamalPublicBCPGKey) pubKey
  174. .getPublicKeyPacket().getKey();
  175. if (!basePubKey.getP().equals(assocPubKey.getP())
  176. || !basePubKey.getG().equals(assocPubKey.getG())
  177. || !basePubKey.getY().equals(assocPubKey.getY())) {
  178. throw new PGPException(
  179. "passed in public key does not match secret key");
  180. }
  181. return new PGPSecretKey(
  182. new SecretKeyPacket(pubKey.getPublicKeyPacket(),
  183. SymmetricKeyAlgorithmTags.NULL, null, null,
  184. new ElGamalSecretBCPGKey(x).getEncoded()),
  185. pubKey);
  186. } else if (keyType.equals("rsa")) {
  187. BigInteger n = readBigInteger("n", inputStream);
  188. BigInteger e = readBigInteger("e", inputStream);
  189. BigInteger[] values = processRSASecretKey(inputStream, n, e,
  190. keyProtectionRemoverFactory);
  191. // TODO: type of RSA key?
  192. RSAPublicBCPGKey basePubKey = new RSAPublicBCPGKey(n, e);
  193. RSAPublicBCPGKey assocPubKey = (RSAPublicBCPGKey) pubKey
  194. .getPublicKeyPacket().getKey();
  195. if (!basePubKey.getModulus().equals(assocPubKey.getModulus())
  196. || !basePubKey.getPublicExponent()
  197. .equals(assocPubKey.getPublicExponent())) {
  198. throw new PGPException(
  199. "passed in public key does not match secret key");
  200. }
  201. return new PGPSecretKey(new SecretKeyPacket(
  202. pubKey.getPublicKeyPacket(),
  203. SymmetricKeyAlgorithmTags.NULL, null, null,
  204. new RSASecretBCPGKey(values[0], values[1], values[2])
  205. .getEncoded()),
  206. pubKey);
  207. } else {
  208. throw new PGPException("unknown key type: " + keyType);
  209. }
  210. }
  211. throw new PGPException("unknown key type found");
  212. }
  213. /**
  214. * Parse a secret key from one of the GPG S expression keys.
  215. *
  216. * @param inputStream
  217. * to read from
  218. * @param keyProtectionRemoverFactory
  219. * for decrypting encrypted keys
  220. * @param fingerPrintCalculator
  221. * for calculating key fingerprints
  222. *
  223. * @return a secret key object.
  224. * @throws IOException
  225. * @throws PGPException
  226. */
  227. public PGPSecretKey parseSecretKey(InputStream inputStream,
  228. PBEProtectionRemoverFactory keyProtectionRemoverFactory,
  229. KeyFingerPrintCalculator fingerPrintCalculator)
  230. throws IOException, PGPException {
  231. SXprUtils.skipOpenParenthesis(inputStream);
  232. String type;
  233. type = SXprUtils.readString(inputStream, inputStream.read());
  234. if (type.equals("protected-private-key")
  235. || type.equals("private-key")) {
  236. SXprUtils.skipOpenParenthesis(inputStream);
  237. String keyType = SXprUtils.readString(inputStream,
  238. inputStream.read());
  239. if (keyType.equals("ecc")) {
  240. SXprUtils.skipOpenParenthesis(inputStream);
  241. String curveID = SXprUtils.readString(inputStream,
  242. inputStream.read());
  243. String curveName = SXprUtils.readString(inputStream,
  244. inputStream.read());
  245. if (curveName.startsWith("NIST ")) {
  246. curveName = curveName.substring("NIST ".length());
  247. }
  248. SXprUtils.skipCloseParenthesis(inputStream);
  249. byte[] qVal;
  250. SXprUtils.skipOpenParenthesis(inputStream);
  251. type = SXprUtils.readString(inputStream, inputStream.read());
  252. if (type.equals("q")) {
  253. qVal = SXprUtils.readBytes(inputStream, inputStream.read());
  254. } else {
  255. throw new PGPException("no q value found");
  256. }
  257. PublicKeyPacket pubPacket = new PublicKeyPacket(
  258. PublicKeyAlgorithmTags.ECDSA, new Date(),
  259. new ECDSAPublicBCPGKey(
  260. ECNamedCurveTable.getOID(curveName),
  261. new BigInteger(1, qVal)));
  262. SXprUtils.skipCloseParenthesis(inputStream);
  263. BigInteger d = processECSecretKey(inputStream, curveID,
  264. curveName, qVal, keyProtectionRemoverFactory);
  265. return new PGPSecretKey(
  266. new SecretKeyPacket(pubPacket,
  267. SymmetricKeyAlgorithmTags.NULL, null, null,
  268. new ECSecretBCPGKey(d).getEncoded()),
  269. new PGPPublicKey(pubPacket, fingerPrintCalculator));
  270. } else if (keyType.equals("dsa")) {
  271. BigInteger p = readBigInteger("p", inputStream);
  272. BigInteger q = readBigInteger("q", inputStream);
  273. BigInteger g = readBigInteger("g", inputStream);
  274. BigInteger y = readBigInteger("y", inputStream);
  275. BigInteger x = processDSASecretKey(inputStream, p, q, g, y,
  276. keyProtectionRemoverFactory);
  277. PublicKeyPacket pubPacket = new PublicKeyPacket(
  278. PublicKeyAlgorithmTags.DSA, new Date(),
  279. new DSAPublicBCPGKey(p, q, g, y));
  280. return new PGPSecretKey(
  281. new SecretKeyPacket(pubPacket,
  282. SymmetricKeyAlgorithmTags.NULL, null, null,
  283. new DSASecretBCPGKey(x).getEncoded()),
  284. new PGPPublicKey(pubPacket, fingerPrintCalculator));
  285. } else if (keyType.equals("elg")) {
  286. BigInteger p = readBigInteger("p", inputStream);
  287. BigInteger g = readBigInteger("g", inputStream);
  288. BigInteger y = readBigInteger("y", inputStream);
  289. BigInteger x = processElGamalSecretKey(inputStream, p, g, y,
  290. keyProtectionRemoverFactory);
  291. PublicKeyPacket pubPacket = new PublicKeyPacket(
  292. PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT, new Date(),
  293. new ElGamalPublicBCPGKey(p, g, y));
  294. return new PGPSecretKey(
  295. new SecretKeyPacket(pubPacket,
  296. SymmetricKeyAlgorithmTags.NULL, null, null,
  297. new ElGamalSecretBCPGKey(x).getEncoded()),
  298. new PGPPublicKey(pubPacket, fingerPrintCalculator));
  299. } else if (keyType.equals("rsa")) {
  300. BigInteger n = readBigInteger("n", inputStream);
  301. BigInteger e = readBigInteger("e", inputStream);
  302. BigInteger[] values = processRSASecretKey(inputStream, n, e,
  303. keyProtectionRemoverFactory);
  304. // TODO: type of RSA key?
  305. PublicKeyPacket pubPacket = new PublicKeyPacket(
  306. PublicKeyAlgorithmTags.RSA_GENERAL, new Date(),
  307. new RSAPublicBCPGKey(n, e));
  308. return new PGPSecretKey(
  309. new SecretKeyPacket(pubPacket,
  310. SymmetricKeyAlgorithmTags.NULL, null, null,
  311. new RSASecretBCPGKey(values[0], values[1],
  312. values[2]).getEncoded()),
  313. new PGPPublicKey(pubPacket, fingerPrintCalculator));
  314. } else {
  315. throw new PGPException("unknown key type: " + keyType);
  316. }
  317. }
  318. throw new PGPException("unknown key type found");
  319. }
  320. private BigInteger readBigInteger(String expectedType,
  321. InputStream inputStream) throws IOException, PGPException {
  322. SXprUtils.skipOpenParenthesis(inputStream);
  323. String type = SXprUtils.readString(inputStream, inputStream.read());
  324. if (!type.equals(expectedType)) {
  325. throw new PGPException(expectedType + " value expected");
  326. }
  327. byte[] nBytes = SXprUtils.readBytes(inputStream, inputStream.read());
  328. BigInteger v = new BigInteger(1, nBytes);
  329. SXprUtils.skipCloseParenthesis(inputStream);
  330. return v;
  331. }
  332. private static byte[][] extractData(InputStream inputStream,
  333. PBEProtectionRemoverFactory keyProtectionRemoverFactory)
  334. throws PGPException, IOException {
  335. byte[] data;
  336. byte[] protectedAt = null;
  337. SXprUtils.skipOpenParenthesis(inputStream);
  338. String type = SXprUtils.readString(inputStream, inputStream.read());
  339. if (type.equals("protected")) {
  340. String protection = SXprUtils.readString(inputStream,
  341. inputStream.read());
  342. SXprUtils.skipOpenParenthesis(inputStream);
  343. S2K s2k = SXprUtils.parseS2K(inputStream);
  344. byte[] iv = SXprUtils.readBytes(inputStream, inputStream.read());
  345. SXprUtils.skipCloseParenthesis(inputStream);
  346. byte[] secKeyData = SXprUtils.readBytes(inputStream,
  347. inputStream.read());
  348. SXprUtils.skipCloseParenthesis(inputStream);
  349. PBESecretKeyDecryptor keyDecryptor = keyProtectionRemoverFactory
  350. .createDecryptor(protection);
  351. // TODO: recognise other algorithms
  352. byte[] key = keyDecryptor.makeKeyFromPassPhrase(
  353. SymmetricKeyAlgorithmTags.AES_128, s2k);
  354. data = keyDecryptor.recoverKeyData(
  355. SymmetricKeyAlgorithmTags.AES_128, key, iv, secKeyData, 0,
  356. secKeyData.length);
  357. // check if protected at is present
  358. if (inputStream.read() == '(') {
  359. ByteArrayOutputStream bOut = new ByteArrayOutputStream();
  360. bOut.write('(');
  361. int ch;
  362. while ((ch = inputStream.read()) >= 0 && ch != ')') {
  363. bOut.write(ch);
  364. }
  365. if (ch != ')') {
  366. throw new IOException("unexpected end to SExpr");
  367. }
  368. bOut.write(')');
  369. protectedAt = bOut.toByteArray();
  370. }
  371. SXprUtils.skipCloseParenthesis(inputStream);
  372. SXprUtils.skipCloseParenthesis(inputStream);
  373. } else if (type.equals("d") || type.equals("x")) {
  374. // JGit modification: unencrypted DSA or ECC keys can have an "x"
  375. // here
  376. return null;
  377. } else {
  378. throw new PGPException("protected block not found");
  379. }
  380. return new byte[][] { data, protectedAt };
  381. }
  382. private BigInteger processDSASecretKey(InputStream inputStream,
  383. BigInteger p, BigInteger q, BigInteger g, BigInteger y,
  384. PBEProtectionRemoverFactory keyProtectionRemoverFactory)
  385. throws IOException, PGPException {
  386. String type;
  387. byte[][] basicData = extractData(inputStream,
  388. keyProtectionRemoverFactory);
  389. // JGit modification: handle unencrypted DSA keys
  390. if (basicData == null) {
  391. byte[] nBytes = SXprUtils.readBytes(inputStream,
  392. inputStream.read());
  393. BigInteger x = new BigInteger(1, nBytes);
  394. SXprUtils.skipCloseParenthesis(inputStream);
  395. return x;
  396. }
  397. byte[] keyData = basicData[0];
  398. byte[] protectedAt = basicData[1];
  399. //
  400. // parse the secret key S-expr
  401. //
  402. InputStream keyIn = new ByteArrayInputStream(keyData);
  403. SXprUtils.skipOpenParenthesis(keyIn);
  404. SXprUtils.skipOpenParenthesis(keyIn);
  405. BigInteger x = readBigInteger("x", keyIn);
  406. SXprUtils.skipCloseParenthesis(keyIn);
  407. // JGit modification: OCB-encrypted keys don't have and don't need a
  408. // hash
  409. if (keyProtectionRemoverFactory instanceof OCBPBEProtectionRemoverFactory) {
  410. return x;
  411. }
  412. SXprUtils.skipOpenParenthesis(keyIn);
  413. type = SXprUtils.readString(keyIn, keyIn.read());
  414. if (!type.equals("hash")) {
  415. throw new PGPException("hash keyword expected");
  416. }
  417. type = SXprUtils.readString(keyIn, keyIn.read());
  418. if (!type.equals("sha1")) {
  419. throw new PGPException("hash keyword expected");
  420. }
  421. byte[] hashBytes = SXprUtils.readBytes(keyIn, keyIn.read());
  422. SXprUtils.skipCloseParenthesis(keyIn);
  423. if (digestProvider != null) {
  424. PGPDigestCalculator digestCalculator = digestProvider
  425. .get(HashAlgorithmTags.SHA1);
  426. OutputStream dOut = digestCalculator.getOutputStream();
  427. dOut.write(Strings.toByteArray("(3:dsa"));
  428. writeCanonical(dOut, "p", p);
  429. writeCanonical(dOut, "q", q);
  430. writeCanonical(dOut, "g", g);
  431. writeCanonical(dOut, "y", y);
  432. writeCanonical(dOut, "x", x);
  433. // check protected-at
  434. if (protectedAt != null) {
  435. dOut.write(protectedAt);
  436. }
  437. dOut.write(Strings.toByteArray(")"));
  438. byte[] check = digestCalculator.getDigest();
  439. if (!Arrays.constantTimeAreEqual(check, hashBytes)) {
  440. throw new PGPException(
  441. "checksum on protected data failed in SExpr");
  442. }
  443. }
  444. return x;
  445. }
  446. private BigInteger processElGamalSecretKey(InputStream inputStream,
  447. BigInteger p, BigInteger g, BigInteger y,
  448. PBEProtectionRemoverFactory keyProtectionRemoverFactory)
  449. throws IOException, PGPException {
  450. String type;
  451. byte[][] basicData = extractData(inputStream,
  452. keyProtectionRemoverFactory);
  453. // JGit modification: handle unencrypted EC keys
  454. if (basicData == null) {
  455. byte[] nBytes = SXprUtils.readBytes(inputStream,
  456. inputStream.read());
  457. BigInteger x = new BigInteger(1, nBytes);
  458. SXprUtils.skipCloseParenthesis(inputStream);
  459. return x;
  460. }
  461. byte[] keyData = basicData[0];
  462. byte[] protectedAt = basicData[1];
  463. //
  464. // parse the secret key S-expr
  465. //
  466. InputStream keyIn = new ByteArrayInputStream(keyData);
  467. SXprUtils.skipOpenParenthesis(keyIn);
  468. SXprUtils.skipOpenParenthesis(keyIn);
  469. BigInteger x = readBigInteger("x", keyIn);
  470. SXprUtils.skipCloseParenthesis(keyIn);
  471. // JGit modification: OCB-encrypted keys don't have and don't need a
  472. // hash
  473. if (keyProtectionRemoverFactory instanceof OCBPBEProtectionRemoverFactory) {
  474. return x;
  475. }
  476. SXprUtils.skipOpenParenthesis(keyIn);
  477. type = SXprUtils.readString(keyIn, keyIn.read());
  478. if (!type.equals("hash")) {
  479. throw new PGPException("hash keyword expected");
  480. }
  481. type = SXprUtils.readString(keyIn, keyIn.read());
  482. if (!type.equals("sha1")) {
  483. throw new PGPException("hash keyword expected");
  484. }
  485. byte[] hashBytes = SXprUtils.readBytes(keyIn, keyIn.read());
  486. SXprUtils.skipCloseParenthesis(keyIn);
  487. if (digestProvider != null) {
  488. PGPDigestCalculator digestCalculator = digestProvider
  489. .get(HashAlgorithmTags.SHA1);
  490. OutputStream dOut = digestCalculator.getOutputStream();
  491. dOut.write(Strings.toByteArray("(3:elg"));
  492. writeCanonical(dOut, "p", p);
  493. writeCanonical(dOut, "g", g);
  494. writeCanonical(dOut, "y", y);
  495. writeCanonical(dOut, "x", x);
  496. // check protected-at
  497. if (protectedAt != null) {
  498. dOut.write(protectedAt);
  499. }
  500. dOut.write(Strings.toByteArray(")"));
  501. byte[] check = digestCalculator.getDigest();
  502. if (!Arrays.constantTimeAreEqual(check, hashBytes)) {
  503. throw new PGPException(
  504. "checksum on protected data failed in SExpr");
  505. }
  506. }
  507. return x;
  508. }
  509. private BigInteger processECSecretKey(InputStream inputStream,
  510. String curveID, String curveName, byte[] qVal,
  511. PBEProtectionRemoverFactory keyProtectionRemoverFactory)
  512. throws IOException, PGPException {
  513. String type;
  514. byte[][] basicData = extractData(inputStream,
  515. keyProtectionRemoverFactory);
  516. // JGit modification: handle unencrypted EC keys
  517. if (basicData == null) {
  518. byte[] nBytes = SXprUtils.readBytes(inputStream,
  519. inputStream.read());
  520. BigInteger d = new BigInteger(1, nBytes);
  521. SXprUtils.skipCloseParenthesis(inputStream);
  522. return d;
  523. }
  524. byte[] keyData = basicData[0];
  525. byte[] protectedAt = basicData[1];
  526. //
  527. // parse the secret key S-expr
  528. //
  529. InputStream keyIn = new ByteArrayInputStream(keyData);
  530. SXprUtils.skipOpenParenthesis(keyIn);
  531. SXprUtils.skipOpenParenthesis(keyIn);
  532. BigInteger d = readBigInteger("d", keyIn);
  533. SXprUtils.skipCloseParenthesis(keyIn);
  534. // JGit modification: OCB-encrypted keys don't have and don't need a
  535. // hash
  536. if (keyProtectionRemoverFactory instanceof OCBPBEProtectionRemoverFactory) {
  537. return d;
  538. }
  539. SXprUtils.skipOpenParenthesis(keyIn);
  540. type = SXprUtils.readString(keyIn, keyIn.read());
  541. if (!type.equals("hash")) {
  542. throw new PGPException("hash keyword expected");
  543. }
  544. type = SXprUtils.readString(keyIn, keyIn.read());
  545. if (!type.equals("sha1")) {
  546. throw new PGPException("hash keyword expected");
  547. }
  548. byte[] hashBytes = SXprUtils.readBytes(keyIn, keyIn.read());
  549. SXprUtils.skipCloseParenthesis(keyIn);
  550. if (digestProvider != null) {
  551. PGPDigestCalculator digestCalculator = digestProvider
  552. .get(HashAlgorithmTags.SHA1);
  553. OutputStream dOut = digestCalculator.getOutputStream();
  554. dOut.write(Strings.toByteArray("(3:ecc"));
  555. dOut.write(Strings.toByteArray("(" + curveID.length() + ":"
  556. + curveID + curveName.length() + ":" + curveName + ")"));
  557. writeCanonical(dOut, "q", qVal);
  558. writeCanonical(dOut, "d", d);
  559. // check protected-at
  560. if (protectedAt != null) {
  561. dOut.write(protectedAt);
  562. }
  563. dOut.write(Strings.toByteArray(")"));
  564. byte[] check = digestCalculator.getDigest();
  565. if (!Arrays.constantTimeAreEqual(check, hashBytes)) {
  566. throw new PGPException(
  567. "checksum on protected data failed in SExpr");
  568. }
  569. }
  570. return d;
  571. }
  572. private BigInteger[] processRSASecretKey(InputStream inputStream,
  573. BigInteger n, BigInteger e,
  574. PBEProtectionRemoverFactory keyProtectionRemoverFactory)
  575. throws IOException, PGPException {
  576. String type;
  577. byte[][] basicData = extractData(inputStream,
  578. keyProtectionRemoverFactory);
  579. byte[] keyData;
  580. byte[] protectedAt = null;
  581. InputStream keyIn;
  582. BigInteger d;
  583. if (basicData == null) {
  584. keyIn = inputStream;
  585. byte[] nBytes = SXprUtils.readBytes(inputStream,
  586. inputStream.read());
  587. d = new BigInteger(1, nBytes);
  588. SXprUtils.skipCloseParenthesis(inputStream);
  589. } else {
  590. keyData = basicData[0];
  591. protectedAt = basicData[1];
  592. keyIn = new ByteArrayInputStream(keyData);
  593. SXprUtils.skipOpenParenthesis(keyIn);
  594. SXprUtils.skipOpenParenthesis(keyIn);
  595. d = readBigInteger("d", keyIn);
  596. }
  597. //
  598. // parse the secret key S-expr
  599. //
  600. BigInteger p = readBigInteger("p", keyIn);
  601. BigInteger q = readBigInteger("q", keyIn);
  602. BigInteger u = readBigInteger("u", keyIn);
  603. // JGit modification: OCB-encrypted keys don't have and don't need a
  604. // hash
  605. if (basicData == null
  606. || keyProtectionRemoverFactory instanceof OCBPBEProtectionRemoverFactory) {
  607. return new BigInteger[] { d, p, q, u };
  608. }
  609. SXprUtils.skipCloseParenthesis(keyIn);
  610. SXprUtils.skipOpenParenthesis(keyIn);
  611. type = SXprUtils.readString(keyIn, keyIn.read());
  612. if (!type.equals("hash")) {
  613. throw new PGPException("hash keyword expected");
  614. }
  615. type = SXprUtils.readString(keyIn, keyIn.read());
  616. if (!type.equals("sha1")) {
  617. throw new PGPException("hash keyword expected");
  618. }
  619. byte[] hashBytes = SXprUtils.readBytes(keyIn, keyIn.read());
  620. SXprUtils.skipCloseParenthesis(keyIn);
  621. if (digestProvider != null) {
  622. PGPDigestCalculator digestCalculator = digestProvider
  623. .get(HashAlgorithmTags.SHA1);
  624. OutputStream dOut = digestCalculator.getOutputStream();
  625. dOut.write(Strings.toByteArray("(3:rsa"));
  626. writeCanonical(dOut, "n", n);
  627. writeCanonical(dOut, "e", e);
  628. writeCanonical(dOut, "d", d);
  629. writeCanonical(dOut, "p", p);
  630. writeCanonical(dOut, "q", q);
  631. writeCanonical(dOut, "u", u);
  632. // check protected-at
  633. if (protectedAt != null) {
  634. dOut.write(protectedAt);
  635. }
  636. dOut.write(Strings.toByteArray(")"));
  637. byte[] check = digestCalculator.getDigest();
  638. if (!Arrays.constantTimeAreEqual(check, hashBytes)) {
  639. throw new PGPException(
  640. "checksum on protected data failed in SExpr");
  641. }
  642. }
  643. return new BigInteger[] { d, p, q, u };
  644. }
  645. private void writeCanonical(OutputStream dOut, String label, BigInteger i)
  646. throws IOException {
  647. writeCanonical(dOut, label, i.toByteArray());
  648. }
  649. private void writeCanonical(OutputStream dOut, String label, byte[] data)
  650. throws IOException {
  651. dOut.write(Strings.toByteArray(
  652. "(" + label.length() + ":" + label + data.length + ":"));
  653. dOut.write(data);
  654. dOut.write(Strings.toByteArray(")"));
  655. }
  656. }