001: package org.bouncycastle.openpgp;
002:
003: import java.io.ByteArrayInputStream;
004: import java.io.ByteArrayOutputStream;
005: import java.io.IOException;
006: import java.io.OutputStream;
007: import java.security.KeyFactory;
008: import java.security.MessageDigest;
009: import java.security.NoSuchAlgorithmException;
010: import java.security.NoSuchProviderException;
011: import java.security.PrivateKey;
012: import java.security.PublicKey;
013: import java.security.SecureRandom;
014: import java.security.interfaces.DSAPrivateKey;
015: import java.security.interfaces.RSAPrivateCrtKey;
016: import java.security.spec.DSAPrivateKeySpec;
017: import java.security.spec.RSAPrivateCrtKeySpec;
018: import java.util.ArrayList;
019: import java.util.Date;
020: import java.util.Iterator;
021: import java.util.List;
022:
023: import javax.crypto.Cipher;
024: import javax.crypto.SecretKey;
025: import javax.crypto.spec.IvParameterSpec;
026:
027: import org.bouncycastle.bcpg.BCPGInputStream;
028: import org.bouncycastle.bcpg.BCPGObject;
029: import org.bouncycastle.bcpg.BCPGOutputStream;
030: import org.bouncycastle.bcpg.ContainedPacket;
031: import org.bouncycastle.bcpg.DSAPublicBCPGKey;
032: import org.bouncycastle.bcpg.DSASecretBCPGKey;
033: import org.bouncycastle.bcpg.ElGamalPublicBCPGKey;
034: import org.bouncycastle.bcpg.ElGamalSecretBCPGKey;
035: import org.bouncycastle.bcpg.HashAlgorithmTags;
036: import org.bouncycastle.bcpg.PublicKeyPacket;
037: import org.bouncycastle.bcpg.RSAPublicBCPGKey;
038: import org.bouncycastle.bcpg.RSASecretBCPGKey;
039: import org.bouncycastle.bcpg.S2K;
040: import org.bouncycastle.bcpg.SecretKeyPacket;
041: import org.bouncycastle.bcpg.SecretSubkeyPacket;
042: import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
043: import org.bouncycastle.bcpg.TrustPacket;
044: import org.bouncycastle.bcpg.UserAttributePacket;
045: import org.bouncycastle.bcpg.UserIDPacket;
046: import org.bouncycastle.jce.interfaces.ElGamalPrivateKey;
047: import org.bouncycastle.jce.spec.ElGamalParameterSpec;
048: import org.bouncycastle.jce.spec.ElGamalPrivateKeySpec;
049:
050: /**
051: * general class to handle a PGP secret key object.
052: */
053: public class PGPSecretKey {
054: SecretKeyPacket secret;
055: TrustPacket trust;
056: List keySigs;
057: List ids;
058: List idTrusts;
059: List idSigs;
060: PGPPublicKey pub;
061: List subSigs = null;
062:
063: /**
064: * copy constructor - master key.
065: */
066: private PGPSecretKey(SecretKeyPacket secret, TrustPacket trust,
067: List keySigs, List ids, List idTrusts, List idSigs,
068: PGPPublicKey pub) {
069: this .secret = secret;
070: this .trust = trust;
071: this .keySigs = keySigs;
072: this .ids = ids;
073: this .idTrusts = idTrusts;
074: this .idSigs = idSigs;
075: this .pub = pub;
076: }
077:
078: /**
079: * copy constructor - subkey.
080: */
081: private PGPSecretKey(SecretKeyPacket secret, TrustPacket trust,
082: List subSigs, PGPPublicKey pub) {
083: this .secret = secret;
084: this .trust = trust;
085: this .subSigs = subSigs;
086: this .pub = pub;
087: }
088:
089: PGPSecretKey(SecretKeyPacket secret, TrustPacket trust,
090: List keySigs, List ids, List idTrusts, List idSigs)
091: throws IOException {
092: this .secret = secret;
093: this .trust = trust;
094: this .keySigs = keySigs;
095: this .ids = ids;
096: this .idTrusts = idTrusts;
097: this .idSigs = idSigs;
098: this .pub = new PGPPublicKey(secret.getPublicKeyPacket(), trust,
099: keySigs, ids, idTrusts, idSigs);
100: }
101:
102: PGPSecretKey(SecretKeyPacket secret, TrustPacket trust, List subSigs)
103: throws IOException {
104: this .secret = secret;
105: this .trust = trust;
106: this .subSigs = subSigs;
107: this .pub = new PGPPublicKey(secret.getPublicKeyPacket(), trust,
108: subSigs);
109: }
110:
111: PGPSecretKey(PGPKeyPair keyPair, TrustPacket trust, List subSigs,
112: int encAlgorithm, char[] passPhrase, boolean useSHA1,
113: SecureRandom rand, String provider) throws PGPException,
114: NoSuchProviderException {
115: this (keyPair, encAlgorithm, passPhrase, useSHA1, rand, provider);
116:
117: this .secret = new SecretSubkeyPacket(secret
118: .getPublicKeyPacket(), secret.getEncAlgorithm(), secret
119: .getS2KUsage(), secret.getS2K(), secret.getIV(), secret
120: .getSecretKeyData());
121: this .trust = trust;
122: this .subSigs = subSigs;
123: this .pub = new PGPPublicKey(keyPair.getPublicKey(), trust,
124: subSigs);
125: }
126:
127: PGPSecretKey(PGPKeyPair keyPair, int encAlgorithm,
128: char[] passPhrase, boolean useSHA1, SecureRandom rand,
129: String provider) throws PGPException,
130: NoSuchProviderException {
131: PublicKeyPacket pubPk;
132: BCPGObject secKey;
133:
134: pubPk = keyPair.getPublicKey().publicPk;
135:
136: switch (keyPair.getPublicKey().getAlgorithm()) {
137: case PGPPublicKey.RSA_ENCRYPT:
138: case PGPPublicKey.RSA_SIGN:
139: case PGPPublicKey.RSA_GENERAL:
140: RSAPrivateCrtKey rsK = (RSAPrivateCrtKey) keyPair
141: .getPrivateKey().getKey();
142:
143: secKey = new RSASecretBCPGKey(rsK.getPrivateExponent(), rsK
144: .getPrimeP(), rsK.getPrimeQ());
145: break;
146: case PGPPublicKey.DSA:
147: DSAPrivateKey dsK = (DSAPrivateKey) keyPair.getPrivateKey()
148: .getKey();
149:
150: secKey = new DSASecretBCPGKey(dsK.getX());
151: break;
152: case PGPPublicKey.ELGAMAL_ENCRYPT:
153: case PGPPublicKey.ELGAMAL_GENERAL:
154: ElGamalPrivateKey esK = (ElGamalPrivateKey) keyPair
155: .getPrivateKey().getKey();
156:
157: secKey = new ElGamalSecretBCPGKey(esK.getX());
158: break;
159: default:
160: throw new PGPException("unknown key class");
161: }
162:
163: String cName = PGPUtil.getSymmetricCipherName(encAlgorithm);
164: Cipher c = null;
165:
166: if (cName != null) {
167: try {
168: c = Cipher.getInstance(cName + "/CFB/NoPadding",
169: provider);
170: } catch (NoSuchProviderException e) {
171: throw e;
172: } catch (Exception e) {
173: throw new PGPException("Exception creating cipher", e);
174: }
175: }
176:
177: try {
178: ByteArrayOutputStream bOut = new ByteArrayOutputStream();
179: BCPGOutputStream pOut = new BCPGOutputStream(bOut);
180:
181: pOut.writeObject(secKey);
182:
183: byte[] keyData = bOut.toByteArray();
184:
185: pOut.write(checksum(useSHA1, keyData, keyData.length));
186:
187: if (c != null) {
188: byte[] iv = new byte[8];
189:
190: rand.nextBytes(iv);
191:
192: S2K s2k = new S2K(HashAlgorithmTags.SHA1, iv, 0x60);
193: SecretKey key = PGPUtil.makeKeyFromPassPhrase(
194: encAlgorithm, s2k, passPhrase, provider);
195:
196: c.init(Cipher.ENCRYPT_MODE, key, rand);
197:
198: iv = c.getIV();
199:
200: byte[] encData = c.doFinal(bOut.toByteArray());
201:
202: if (useSHA1) {
203: this .secret = new SecretKeyPacket(pubPk,
204: encAlgorithm, SecretKeyPacket.USAGE_SHA1,
205: s2k, iv, encData);
206: } else {
207: this .secret = new SecretKeyPacket(pubPk,
208: encAlgorithm,
209: SecretKeyPacket.USAGE_CHECKSUM, s2k, iv,
210: encData);
211: }
212:
213: this .trust = null;
214: } else {
215: this .secret = new SecretKeyPacket(pubPk, encAlgorithm,
216: null, null, bOut.toByteArray());
217: this .trust = null;
218: }
219: } catch (PGPException e) {
220: throw e;
221: } catch (Exception e) {
222: throw new PGPException("Exception encrypting key", e);
223: }
224:
225: this .keySigs = new ArrayList();
226: }
227:
228: public PGPSecretKey(int certificationLevel, PGPKeyPair keyPair,
229: String id, int encAlgorithm, char[] passPhrase,
230: PGPSignatureSubpacketVector hashedPcks,
231: PGPSignatureSubpacketVector unhashedPcks,
232: SecureRandom rand, String provider) throws PGPException,
233: NoSuchProviderException {
234: this (certificationLevel, keyPair, id, encAlgorithm, passPhrase,
235: false, hashedPcks, unhashedPcks, rand, provider);
236: }
237:
238: public PGPSecretKey(int certificationLevel, PGPKeyPair keyPair,
239: String id, int encAlgorithm, char[] passPhrase,
240: boolean useSHA1, PGPSignatureSubpacketVector hashedPcks,
241: PGPSignatureSubpacketVector unhashedPcks,
242: SecureRandom rand, String provider) throws PGPException,
243: NoSuchProviderException {
244: this (keyPair, encAlgorithm, passPhrase, useSHA1, rand, provider);
245:
246: try {
247: this .trust = null;
248:
249: this .ids = new ArrayList();
250: ids.add(id);
251:
252: this .idTrusts = new ArrayList();
253: idTrusts.add(null);
254:
255: this .idSigs = new ArrayList();
256:
257: PGPSignatureGenerator sGen = new PGPSignatureGenerator(
258: keyPair.getPublicKey().getAlgorithm(),
259: HashAlgorithmTags.SHA1, provider);
260:
261: //
262: // generate the certification
263: //
264: sGen.initSign(certificationLevel, keyPair.getPrivateKey());
265:
266: sGen.setHashedSubpackets(hashedPcks);
267: sGen.setUnhashedSubpackets(unhashedPcks);
268:
269: PGPSignature certification = sGen.generateCertification(id,
270: keyPair.getPublicKey());
271:
272: this .pub = PGPPublicKey.addCertification(keyPair
273: .getPublicKey(), id, certification);
274:
275: List sigList = new ArrayList();
276:
277: sigList.add(certification);
278:
279: idSigs.add(sigList);
280: } catch (PGPException e) {
281: throw e;
282: } catch (Exception e) {
283: throw new PGPException("Exception encrypting key", e);
284: }
285: }
286:
287: public PGPSecretKey(int certificationLevel, int algorithm,
288: PublicKey pubKey, PrivateKey privKey, Date time, String id,
289: int encAlgorithm, char[] passPhrase,
290: PGPSignatureSubpacketVector hashedPcks,
291: PGPSignatureSubpacketVector unhashedPcks,
292: SecureRandom rand, String provider) throws PGPException,
293: NoSuchProviderException {
294: this (certificationLevel, new PGPKeyPair(algorithm, pubKey,
295: privKey, time, provider), id, encAlgorithm, passPhrase,
296: hashedPcks, unhashedPcks, rand, provider);
297: }
298:
299: public PGPSecretKey(int certificationLevel, int algorithm,
300: PublicKey pubKey, PrivateKey privKey, Date time, String id,
301: int encAlgorithm, char[] passPhrase, boolean useSHA1,
302: PGPSignatureSubpacketVector hashedPcks,
303: PGPSignatureSubpacketVector unhashedPcks,
304: SecureRandom rand, String provider) throws PGPException,
305: NoSuchProviderException {
306: this (certificationLevel, new PGPKeyPair(algorithm, pubKey,
307: privKey, time, provider), id, encAlgorithm, passPhrase,
308: useSHA1, hashedPcks, unhashedPcks, rand, provider);
309: }
310:
311: /**
312: * return true if this key is marked as suitable for signature generation.
313: */
314: public boolean isSigningKey() {
315: int algorithm = pub.getAlgorithm();
316:
317: return ((algorithm == PGPPublicKey.RSA_GENERAL)
318: || (algorithm == PGPPublicKey.RSA_SIGN)
319: || (algorithm == PGPPublicKey.DSA)
320: || (algorithm == PGPPublicKey.ECDSA) || (algorithm == PGPPublicKey.ELGAMAL_GENERAL));
321: }
322:
323: /**
324: * Return true if this is a master key.
325: * @return true if a master key.
326: */
327: public boolean isMasterKey() {
328: return (subSigs == null);
329: }
330:
331: /**
332: * return the algorithm the key is encrypted with.
333: *
334: * @return the algorithm used to encrypt the secret key.
335: */
336: public int getKeyEncryptionAlgorithm() {
337: return secret.getEncAlgorithm();
338: }
339:
340: /**
341: * Return the keyID of the public key associated with this key.
342: *
343: * @return the keyID associated with this key.
344: */
345: public long getKeyID() {
346: return pub.getKeyID();
347: }
348:
349: /**
350: * Return the public key associated with this key.
351: *
352: * @return the public key for this key.
353: */
354: public PGPPublicKey getPublicKey() {
355: return pub;
356: }
357:
358: /**
359: * Return any userIDs associated with the key.
360: *
361: * @return an iterator of Strings.
362: */
363: public Iterator getUserIDs() {
364: return pub.getUserIDs();
365: }
366:
367: /**
368: * Return any user attribute vectors associated with the key.
369: *
370: * @return an iterator of Strings.
371: */
372: public Iterator getUserAttributes() {
373: return pub.getUserAttributes();
374: }
375:
376: private byte[] extractKeyData(char[] passPhrase, String provider)
377: throws PGPException, NoSuchProviderException {
378: String cName = PGPUtil.getSymmetricCipherName(secret
379: .getEncAlgorithm());
380: Cipher c = null;
381:
382: if (cName != null) {
383: try {
384: c = Cipher.getInstance(cName + "/CFB/NoPadding",
385: provider);
386: } catch (NoSuchProviderException e) {
387: throw e;
388: } catch (Exception e) {
389: throw new PGPException("Exception creating cipher", e);
390: }
391: }
392:
393: byte[] encData = secret.getSecretKeyData();
394: byte[] data = null;
395:
396: try {
397: if (c != null) {
398: try {
399: if (secret.getPublicKeyPacket().getVersion() == 4) {
400: IvParameterSpec ivSpec = new IvParameterSpec(
401: secret.getIV());
402:
403: SecretKey key = PGPUtil
404: .makeKeyFromPassPhrase(secret
405: .getEncAlgorithm(), secret
406: .getS2K(), passPhrase, provider);
407:
408: c.init(Cipher.DECRYPT_MODE, key, ivSpec);
409:
410: data = c.doFinal(encData, 0, encData.length);
411:
412: boolean useSHA1 = secret.getS2KUsage() == SecretKeyPacket.USAGE_SHA1;
413: byte[] check = checksum(useSHA1, data,
414: (useSHA1) ? data.length - 20
415: : data.length - 2);
416:
417: for (int i = 0; i != check.length; i++) {
418: if (check[i] != data[data.length
419: - check.length + i]) {
420: throw new PGPException(
421: "checksum mismatch at " + i
422: + " of " + check.length);
423: }
424: }
425: } else // version 2 or 3, RSA only.
426: {
427: SecretKey key = PGPUtil
428: .makeKeyFromPassPhrase(secret
429: .getEncAlgorithm(), secret
430: .getS2K(), passPhrase, provider);
431:
432: data = new byte[encData.length];
433:
434: byte[] iv = new byte[secret.getIV().length];
435:
436: System.arraycopy(secret.getIV(), 0, iv, 0,
437: iv.length);
438:
439: //
440: // read in the four numbers
441: //
442: int pos = 0;
443:
444: for (int i = 0; i != 4; i++) {
445: c.init(Cipher.DECRYPT_MODE, key,
446: new IvParameterSpec(iv));
447:
448: int encLen = (((encData[pos] << 8) | (encData[pos + 1] & 0xff)) + 7) / 8;
449:
450: data[pos] = encData[pos];
451: data[pos + 1] = encData[pos + 1];
452:
453: c.doFinal(encData, pos + 2, encLen, data,
454: pos + 2);
455: pos += 2 + encLen;
456:
457: if (i != 3) {
458: System.arraycopy(encData, pos
459: - iv.length, iv, 0, iv.length);
460: }
461: }
462:
463: //
464: // verify checksum
465: //
466:
467: int cs = ((encData[pos] << 8) & 0xff00)
468: | (encData[pos + 1] & 0xff);
469: int calcCs = 0;
470: for (int j = 0; j < data.length - 2; j++) {
471: calcCs += data[j] & 0xff;
472: }
473:
474: calcCs &= 0xffff;
475: if (calcCs != cs) {
476: throw new PGPException(
477: "checksum mismatch: passphrase wrong, expected "
478: + Integer.toHexString(cs)
479: + " found "
480: + Integer
481: .toHexString(calcCs));
482: }
483: }
484: } catch (PGPException e) {
485: throw e;
486: } catch (Exception e) {
487: throw new PGPException("Exception decrypting key",
488: e);
489: }
490: } else {
491: data = encData;
492: }
493:
494: return data;
495: } catch (PGPException e) {
496: throw e;
497: } catch (Exception e) {
498: throw new PGPException("Exception constructing key", e);
499: }
500: }
501:
502: /**
503: * Extract a PGPPrivate key from the SecretKey's encrypted contents.
504: *
505: * @param passPhrase
506: * @param provider
507: * @return PGPPrivateKey
508: * @throws PGPException
509: * @throws NoSuchProviderException
510: */
511: public PGPPrivateKey extractPrivateKey(char[] passPhrase,
512: String provider) throws PGPException,
513: NoSuchProviderException {
514: PublicKeyPacket pubPk = secret.getPublicKeyPacket();
515:
516: if (secret.getSecretKeyData() == null) {
517: return null;
518: }
519:
520: try {
521: KeyFactory fact;
522: byte[] data = extractKeyData(passPhrase, provider);
523: BCPGInputStream in = new BCPGInputStream(
524: new ByteArrayInputStream(data));
525:
526: switch (pubPk.getAlgorithm()) {
527: case PGPPublicKey.RSA_ENCRYPT:
528: case PGPPublicKey.RSA_GENERAL:
529: case PGPPublicKey.RSA_SIGN:
530: RSAPublicBCPGKey rsaPub = (RSAPublicBCPGKey) pubPk
531: .getKey();
532: RSASecretBCPGKey rsaPriv = new RSASecretBCPGKey(in);
533: RSAPrivateCrtKeySpec rsaPrivSpec = new RSAPrivateCrtKeySpec(
534: rsaPriv.getModulus(), rsaPub
535: .getPublicExponent(), rsaPriv
536: .getPrivateExponent(), rsaPriv
537: .getPrimeP(), rsaPriv.getPrimeQ(),
538: rsaPriv.getPrimeExponentP(), rsaPriv
539: .getPrimeExponentQ(), rsaPriv
540: .getCrtCoefficient());
541:
542: fact = KeyFactory.getInstance("RSA", provider);
543:
544: return new PGPPrivateKey(fact
545: .generatePrivate(rsaPrivSpec), this .getKeyID());
546: case PGPPublicKey.DSA:
547: DSAPublicBCPGKey dsaPub = (DSAPublicBCPGKey) pubPk
548: .getKey();
549: DSASecretBCPGKey dsaPriv = new DSASecretBCPGKey(in);
550: DSAPrivateKeySpec dsaPrivSpec = new DSAPrivateKeySpec(
551: dsaPriv.getX(), dsaPub.getP(), dsaPub.getQ(),
552: dsaPub.getG());
553:
554: fact = KeyFactory.getInstance("DSA", provider);
555:
556: return new PGPPrivateKey(fact
557: .generatePrivate(dsaPrivSpec), this .getKeyID());
558: case PGPPublicKey.ELGAMAL_ENCRYPT:
559: case PGPPublicKey.ELGAMAL_GENERAL:
560: ElGamalPublicBCPGKey elPub = (ElGamalPublicBCPGKey) pubPk
561: .getKey();
562: ElGamalSecretBCPGKey elPriv = new ElGamalSecretBCPGKey(
563: in);
564: ElGamalPrivateKeySpec elSpec = new ElGamalPrivateKeySpec(
565: elPriv.getX(), new ElGamalParameterSpec(elPub
566: .getP(), elPub.getG()));
567:
568: fact = KeyFactory.getInstance("ElGamal", provider);
569:
570: return new PGPPrivateKey(fact.generatePrivate(elSpec),
571: this .getKeyID());
572: default:
573: throw new PGPException(
574: "unknown public key algorithm encountered");
575: }
576: } catch (PGPException e) {
577: throw e;
578: } catch (Exception e) {
579: throw new PGPException("Exception constructing key", e);
580: }
581: }
582:
583: private static byte[] checksum(boolean useSHA1, byte[] bytes,
584: int length) throws PGPException {
585: if (useSHA1) {
586: try {
587: MessageDigest dig = MessageDigest.getInstance("SHA1");
588:
589: dig.update(bytes, 0, length);
590:
591: return dig.digest();
592: } catch (NoSuchAlgorithmException e) {
593: throw new PGPException("Can't find SHA-1", e);
594: }
595: } else {
596: int checksum = 0;
597:
598: for (int i = 0; i != length; i++) {
599: checksum += bytes[i] & 0xff;
600: }
601:
602: byte[] check = new byte[2];
603:
604: check[0] = (byte) (checksum >> 8);
605: check[1] = (byte) checksum;
606:
607: return check;
608: }
609: }
610:
611: public byte[] getEncoded() throws IOException {
612: ByteArrayOutputStream bOut = new ByteArrayOutputStream();
613:
614: this .encode(bOut);
615:
616: return bOut.toByteArray();
617: }
618:
619: public void encode(OutputStream outStream) throws IOException {
620: BCPGOutputStream out;
621:
622: if (outStream instanceof BCPGOutputStream) {
623: out = (BCPGOutputStream) outStream;
624: } else {
625: out = new BCPGOutputStream(outStream);
626: }
627:
628: out.writePacket(secret);
629: if (trust != null) {
630: out.writePacket(trust);
631: }
632:
633: if (subSigs == null) // is not a sub key
634: {
635: for (int i = 0; i != keySigs.size(); i++) {
636: ((PGPSignature) keySigs.get(i)).encode(out);
637: }
638:
639: for (int i = 0; i != ids.size(); i++) {
640: if (ids.get(i) instanceof String) {
641: String id = (String) ids.get(i);
642:
643: out.writePacket(new UserIDPacket(id));
644: } else {
645: PGPUserAttributeSubpacketVector v = (PGPUserAttributeSubpacketVector) ids
646: .get(i);
647:
648: out.writePacket(new UserAttributePacket(v
649: .toSubpacketArray()));
650: }
651:
652: if (idTrusts.get(i) != null) {
653: out.writePacket((ContainedPacket) idTrusts.get(i));
654: }
655:
656: List sigs = (ArrayList) idSigs.get(i);
657:
658: for (int j = 0; j != sigs.size(); j++) {
659: ((PGPSignature) sigs.get(j)).encode(out);
660: }
661: }
662: } else {
663: for (int j = 0; j != subSigs.size(); j++) {
664: ((PGPSignature) subSigs.get(j)).encode(out);
665: }
666: }
667: }
668:
669: /**
670: * Return a copy of the passed in secret key, encrypted using a new
671: * password and the passed in algorithm.
672: *
673: * @param key the PGPSecretKey to be copied.
674: * @param oldPassPhrase the current password for key.
675: * @param newPassPhrase the new password for the key.
676: * @param newEncAlgorithm the algorithm to be used for the encryption.
677: * @param rand source of randomness.
678: * @param provider the provider to use
679: */
680: public static PGPSecretKey copyWithNewPassword(PGPSecretKey key,
681: char[] oldPassPhrase, char[] newPassPhrase,
682: int newEncAlgorithm, SecureRandom rand, String provider)
683: throws PGPException, NoSuchProviderException {
684: byte[] rawKeyData = key.extractKeyData(oldPassPhrase, provider);
685: int s2kUsage = key.secret.getS2KUsage();
686: byte[] iv = null;
687: S2K s2k = null;
688: byte[] keyData = null;
689:
690: if (newEncAlgorithm == SymmetricKeyAlgorithmTags.NULL) {
691: s2kUsage = SecretKeyPacket.USAGE_NONE;
692: if (key.secret.getS2KUsage() == SecretKeyPacket.USAGE_SHA1) // SHA-1 hash, need to rewrite checksum
693: {
694: keyData = new byte[rawKeyData.length - 18];
695:
696: System.arraycopy(rawKeyData, 0, keyData, 0,
697: keyData.length - 2);
698:
699: byte[] check = checksum(false, keyData,
700: keyData.length - 2);
701:
702: keyData[keyData.length - 2] = check[0];
703: keyData[keyData.length - 1] = check[1];
704: } else {
705: keyData = rawKeyData;
706: }
707: } else {
708: Cipher c = null;
709: String cName = PGPUtil
710: .getSymmetricCipherName(newEncAlgorithm);
711:
712: try {
713: c = Cipher.getInstance(cName + "/CFB/NoPadding",
714: provider);
715: } catch (NoSuchProviderException e) {
716: throw e;
717: } catch (Exception e) {
718: throw new PGPException("Exception creating cipher", e);
719: }
720:
721: iv = new byte[8];
722:
723: rand.nextBytes(iv);
724:
725: s2k = new S2K(HashAlgorithmTags.SHA1, iv, 0x60);
726:
727: try {
728: SecretKey sKey = PGPUtil.makeKeyFromPassPhrase(
729: newEncAlgorithm, s2k, newPassPhrase, provider);
730:
731: c.init(Cipher.ENCRYPT_MODE, sKey, rand);
732:
733: iv = c.getIV();
734:
735: keyData = c.doFinal(rawKeyData);
736: } catch (PGPException e) {
737: throw e;
738: } catch (Exception e) {
739: throw new PGPException("Exception encrypting key", e);
740: }
741: }
742:
743: SecretKeyPacket secret = null;
744: if (key.secret instanceof SecretSubkeyPacket) {
745: secret = new SecretSubkeyPacket(key.secret
746: .getPublicKeyPacket(), newEncAlgorithm, s2kUsage,
747: s2k, iv, keyData);
748: } else {
749: secret = new SecretKeyPacket(key.secret
750: .getPublicKeyPacket(), newEncAlgorithm, s2kUsage,
751: s2k, iv, keyData);
752: }
753:
754: if (key.subSigs == null) {
755: return new PGPSecretKey(secret, key.trust, key.keySigs,
756: key.ids, key.idTrusts, key.idSigs, key.pub);
757: } else {
758: return new PGPSecretKey(secret, key.trust, key.subSigs,
759: key.pub);
760: }
761: }
762: }
|