Example usage for org.bouncycastle.openpgp PGPSecretKeyRing insertSecretKey

List of usage examples for org.bouncycastle.openpgp PGPSecretKeyRing insertSecretKey

Introduction

In this page you can find the example usage for org.bouncycastle.openpgp PGPSecretKeyRing insertSecretKey.

Prototype

public static PGPSecretKeyRing insertSecretKey(PGPSecretKeyRing secRing, PGPSecretKey secKey) 

Source Link

Document

Returns a new key ring with the secret key passed in either added or replacing an existing one with the same key ID.

Usage

From source file:org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing.java

License:Open Source License

/** Create a dummy secret ring from this key */
public UncachedKeyRing createDivertSecretRing(byte[] cardAid, long[] subKeyIds) {
    PGPSecretKeyRing secRing = PGPSecretKeyRing.constructDummyFromPublic(getRing(), cardAid);

    if (subKeyIds == null) {
        return new UncachedKeyRing(secRing);
    }/*from  ww  w . j  a  v  a2s . co m*/

    // if only specific subkeys should be promoted, construct a
    // stripped dummy, then move divert-to-card keys over
    PGPSecretKeyRing newRing = PGPSecretKeyRing.constructDummyFromPublic(getRing());
    for (long subKeyId : subKeyIds) {
        PGPSecretKey key = secRing.getSecretKey(subKeyId);
        if (key != null) {
            newRing = PGPSecretKeyRing.insertSecretKey(newRing, key);
        }
    }

    return new UncachedKeyRing(newRing);

}

From source file:org.sufficientlysecure.keychain.pgp.PgpKeyOperation.java

License:Open Source License

private PgpEditKeyResult internal(PGPSecretKeyRing sKR, PGPSecretKey masterSecretKey, int masterKeyFlags,
        long masterKeyExpiry, CryptoInputParcel cryptoInput, SaveKeyringParcel saveParcel, OperationLog log,
        int indent) {

    SecurityTokenSignOperationsBuilder nfcSignOps = new SecurityTokenSignOperationsBuilder(
            cryptoInput.getSignatureTime(), masterSecretKey.getKeyID(), masterSecretKey.getKeyID());
    SecurityTokenKeyToCardOperationsBuilder nfcKeyToCardOps = new SecurityTokenKeyToCardOperationsBuilder(
            masterSecretKey.getKeyID());

    progress(R.string.progress_modify, 0);

    PGPPublicKey masterPublicKey = masterSecretKey.getPublicKey();

    PGPPrivateKey masterPrivateKey;/*w w w .  ja  va  2s  .com*/

    if (isDivertToCard(masterSecretKey)) {
        masterPrivateKey = null;
        log.add(LogType.MSG_MF_DIVERT, indent);
    } else {

        // 1. Unlock private key
        progress(R.string.progress_modify_unlock, 10);
        log.add(LogType.MSG_MF_UNLOCK, indent);
        {
            try {
                PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
                        .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME)
                        .build(cryptoInput.getPassphrase().getCharArray());
                masterPrivateKey = masterSecretKey.extractPrivateKey(keyDecryptor);
            } catch (PGPException e) {
                log.add(LogType.MSG_MF_UNLOCK_ERROR, indent + 1);
                return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
            }
        }
    }

    try {

        // Check if we were cancelled
        if (checkCancelled()) {
            log.add(LogType.MSG_OPERATION_CANCELLED, indent);
            return new PgpEditKeyResult(PgpEditKeyResult.RESULT_CANCELLED, log, null);
        }

        { // work on master secret key

            PGPPublicKey modifiedPublicKey = masterPublicKey;

            // 2a. Add certificates for new user ids
            subProgressPush(15, 23);
            for (int i = 0; i < saveParcel.mAddUserIds.size(); i++) {

                progress(R.string.progress_modify_adduid, (i - 1) * (100 / saveParcel.mAddUserIds.size()));
                String userId = saveParcel.mAddUserIds.get(i);
                log.add(LogType.MSG_MF_UID_ADD, indent, userId);

                if ("".equals(userId)) {
                    log.add(LogType.MSG_MF_UID_ERROR_EMPTY, indent + 1);
                    return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
                }

                // this operation supersedes all previous binding and revocation certificates,
                // so remove those to retain assertions from canonicalization for later operations
                @SuppressWarnings("unchecked")
                Iterator<PGPSignature> it = modifiedPublicKey.getSignaturesForID(userId);
                if (it != null) {
                    for (PGPSignature cert : new IterableIterator<>(it)) {
                        if (cert.getKeyID() != masterPublicKey.getKeyID()) {
                            // foreign certificate?! error error error
                            log.add(LogType.MSG_MF_ERROR_INTEGRITY, indent);
                            return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
                        }
                        if (cert.getSignatureType() == PGPSignature.CERTIFICATION_REVOCATION
                                || cert.getSignatureType() == PGPSignature.NO_CERTIFICATION
                                || cert.getSignatureType() == PGPSignature.CASUAL_CERTIFICATION
                                || cert.getSignatureType() == PGPSignature.POSITIVE_CERTIFICATION
                                || cert.getSignatureType() == PGPSignature.DEFAULT_CERTIFICATION) {
                            modifiedPublicKey = PGPPublicKey.removeCertification(modifiedPublicKey, userId,
                                    cert);
                        }
                    }
                }

                // if it's supposed to be primary, we can do that here as well
                boolean isPrimary = saveParcel.mChangePrimaryUserId != null
                        && userId.equals(saveParcel.mChangePrimaryUserId);
                // generate and add new certificate
                try {
                    PGPSignature cert = generateUserIdSignature(
                            getSignatureGenerator(masterSecretKey, cryptoInput), cryptoInput.getSignatureTime(),
                            masterPrivateKey, masterPublicKey, userId, isPrimary, masterKeyFlags,
                            masterKeyExpiry);
                    modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, userId, cert);
                } catch (NfcInteractionNeeded e) {
                    nfcSignOps.addHash(e.hashToSign, e.hashAlgo);
                }
            }
            subProgressPop();

            // 2b. Add certificates for new user ids
            subProgressPush(23, 32);
            for (int i = 0; i < saveParcel.mAddUserAttribute.size(); i++) {

                progress(R.string.progress_modify_adduat,
                        (i - 1) * (100 / saveParcel.mAddUserAttribute.size()));
                WrappedUserAttribute attribute = saveParcel.mAddUserAttribute.get(i);

                switch (attribute.getType()) {
                // the 'none' type must not succeed
                case WrappedUserAttribute.UAT_NONE:
                    log.add(LogType.MSG_MF_UAT_ERROR_EMPTY, indent);
                    return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
                case WrappedUserAttribute.UAT_IMAGE:
                    log.add(LogType.MSG_MF_UAT_ADD_IMAGE, indent);
                    break;
                default:
                    log.add(LogType.MSG_MF_UAT_ADD_UNKNOWN, indent);
                    break;
                }

                PGPUserAttributeSubpacketVector vector = attribute.getVector();

                // generate and add new certificate
                try {
                    PGPSignature cert = generateUserAttributeSignature(
                            getSignatureGenerator(masterSecretKey, cryptoInput), cryptoInput.getSignatureTime(),
                            masterPrivateKey, masterPublicKey, vector, masterKeyFlags, masterKeyExpiry);
                    modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, vector, cert);
                } catch (NfcInteractionNeeded e) {
                    nfcSignOps.addHash(e.hashToSign, e.hashAlgo);
                }
            }
            subProgressPop();

            // 2c. Add revocations for revoked user ids
            subProgressPush(32, 40);
            for (int i = 0; i < saveParcel.mRevokeUserIds.size(); i++) {

                progress(R.string.progress_modify_revokeuid,
                        (i - 1) * (100 / saveParcel.mRevokeUserIds.size()));
                String userId = saveParcel.mRevokeUserIds.get(i);
                log.add(LogType.MSG_MF_UID_REVOKE, indent, userId);

                // Make sure the user id exists (yes these are 10 LoC in Java!)
                boolean exists = false;
                //noinspection unchecked
                for (String uid : new IterableIterator<String>(modifiedPublicKey.getUserIDs())) {
                    if (userId.equals(uid)) {
                        exists = true;
                        break;
                    }
                }
                if (!exists) {
                    log.add(LogType.MSG_MF_ERROR_NOEXIST_REVOKE, indent);
                    return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
                }

                // a duplicate revocation will be removed during canonicalization, so no need to
                // take care of that here.
                try {
                    PGPSignature cert = generateRevocationSignature(
                            getSignatureGenerator(masterSecretKey, cryptoInput), cryptoInput.getSignatureTime(),
                            masterPrivateKey, masterPublicKey, userId);
                    modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, userId, cert);
                } catch (NfcInteractionNeeded e) {
                    nfcSignOps.addHash(e.hashToSign, e.hashAlgo);
                }
            }
            subProgressPop();

            // 3. If primary user id changed, generate new certificates for both old and new
            if (saveParcel.mChangePrimaryUserId != null) {
                progress(R.string.progress_modify_primaryuid, 40);

                // keep track if we actually changed one
                boolean ok = false;
                log.add(LogType.MSG_MF_UID_PRIMARY, indent, saveParcel.mChangePrimaryUserId);
                indent += 1;

                // we work on the modifiedPublicKey here, to respect new or newly revoked uids
                // noinspection unchecked
                for (String userId : new IterableIterator<String>(modifiedPublicKey.getUserIDs())) {
                    boolean isRevoked = false;
                    PGPSignature currentCert = null;
                    // noinspection unchecked
                    for (PGPSignature cert : new IterableIterator<PGPSignature>(
                            modifiedPublicKey.getSignaturesForID(userId))) {
                        if (cert.getKeyID() != masterPublicKey.getKeyID()) {
                            // foreign certificate?! error error error
                            log.add(LogType.MSG_MF_ERROR_INTEGRITY, indent);
                            return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
                        }
                        // we know from canonicalization that if there is any revocation here, it
                        // is valid and not superseded by a newer certification.
                        if (cert.getSignatureType() == PGPSignature.CERTIFICATION_REVOCATION) {
                            isRevoked = true;
                            continue;
                        }
                        // we know from canonicalization that there is only one binding
                        // certification here, so we can just work with the first one.
                        if (cert.getSignatureType() == PGPSignature.NO_CERTIFICATION
                                || cert.getSignatureType() == PGPSignature.CASUAL_CERTIFICATION
                                || cert.getSignatureType() == PGPSignature.POSITIVE_CERTIFICATION
                                || cert.getSignatureType() == PGPSignature.DEFAULT_CERTIFICATION) {
                            currentCert = cert;
                        }
                    }

                    if (currentCert == null) {
                        // no certificate found?! error error error
                        log.add(LogType.MSG_MF_ERROR_INTEGRITY, indent);
                        return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
                    }

                    // we definitely should not update certifications of revoked keys, so just leave it.
                    if (isRevoked) {
                        // revoked user ids cannot be primary!
                        if (userId.equals(saveParcel.mChangePrimaryUserId)) {
                            log.add(LogType.MSG_MF_ERROR_REVOKED_PRIMARY, indent);
                            return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
                        }
                        continue;
                    }

                    // if this is~ the/a primary user id
                    if (currentCert.getHashedSubPackets() != null
                            && currentCert.getHashedSubPackets().isPrimaryUserID()) {
                        // if it's the one we want, just leave it as is
                        if (userId.equals(saveParcel.mChangePrimaryUserId)) {
                            ok = true;
                            continue;
                        }
                        // otherwise, generate new non-primary certification
                        log.add(LogType.MSG_MF_PRIMARY_REPLACE_OLD, indent);
                        modifiedPublicKey = PGPPublicKey.removeCertification(modifiedPublicKey, userId,
                                currentCert);
                        try {
                            PGPSignature newCert = generateUserIdSignature(
                                    getSignatureGenerator(masterSecretKey, cryptoInput),
                                    cryptoInput.getSignatureTime(), masterPrivateKey, masterPublicKey, userId,
                                    false, masterKeyFlags, masterKeyExpiry);
                            modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, userId,
                                    newCert);
                        } catch (NfcInteractionNeeded e) {
                            nfcSignOps.addHash(e.hashToSign, e.hashAlgo);
                        }

                        continue;
                    }

                    // if we are here, this is not currently a primary user id

                    // if it should be
                    if (userId.equals(saveParcel.mChangePrimaryUserId)) {
                        // add shiny new primary user id certificate
                        log.add(LogType.MSG_MF_PRIMARY_NEW, indent);
                        modifiedPublicKey = PGPPublicKey.removeCertification(modifiedPublicKey, userId,
                                currentCert);
                        try {
                            PGPSignature newCert = generateUserIdSignature(
                                    getSignatureGenerator(masterSecretKey, cryptoInput),
                                    cryptoInput.getSignatureTime(), masterPrivateKey, masterPublicKey, userId,
                                    true, masterKeyFlags, masterKeyExpiry);
                            modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, userId,
                                    newCert);
                        } catch (NfcInteractionNeeded e) {
                            nfcSignOps.addHash(e.hashToSign, e.hashAlgo);
                        }
                        ok = true;
                    }

                    // user id is not primary and is not supposed to be - nothing to do here.

                }

                indent -= 1;

                if (!ok) {
                    log.add(LogType.MSG_MF_ERROR_NOEXIST_PRIMARY, indent);
                    return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
                }
            }

            // Update the secret key ring
            if (modifiedPublicKey != masterPublicKey) {
                masterSecretKey = PGPSecretKey.replacePublicKey(masterSecretKey, modifiedPublicKey);
                masterPublicKey = modifiedPublicKey;
                sKR = PGPSecretKeyRing.insertSecretKey(sKR, masterSecretKey);
            }

        }

        // Check if we were cancelled - again
        if (checkCancelled()) {
            log.add(LogType.MSG_OPERATION_CANCELLED, indent);
            return new PgpEditKeyResult(PgpEditKeyResult.RESULT_CANCELLED, log, null);
        }

        // 4a. For each subkey change, generate new subkey binding certificate
        subProgressPush(50, 60);
        for (int i = 0; i < saveParcel.mChangeSubKeys.size(); i++) {

            progress(R.string.progress_modify_subkeychange, (i - 1) * (100 / saveParcel.mChangeSubKeys.size()));
            SaveKeyringParcel.SubkeyChange change = saveParcel.mChangeSubKeys.get(i);
            log.add(LogType.MSG_MF_SUBKEY_CHANGE, indent, KeyFormattingUtils.convertKeyIdToHex(change.mKeyId));

            PGPSecretKey sKey = sKR.getSecretKey(change.mKeyId);
            if (sKey == null) {
                log.add(LogType.MSG_MF_ERROR_SUBKEY_MISSING, indent + 1,
                        KeyFormattingUtils.convertKeyIdToHex(change.mKeyId));
                return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
            }

            if (change.mDummyStrip) {
                // IT'S DANGEROUS~
                // no really, it is. this operation irrevocably removes the private key data from the key
                sKey = PGPSecretKey.constructGnuDummyKey(sKey.getPublicKey());
                sKR = PGPSecretKeyRing.insertSecretKey(sKR, sKey);
            } else if (change.mMoveKeyToSecurityToken) {
                if (checkSecurityTokenCompatibility(sKey, log, indent + 1)) {
                    log.add(LogType.MSG_MF_KEYTOCARD_START, indent + 1,
                            KeyFormattingUtils.convertKeyIdToHex(change.mKeyId));
                    nfcKeyToCardOps.addSubkey(change.mKeyId);
                } else {
                    // Appropriate log message already set by checkSecurityTokenCompatibility
                    return new PgpEditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
                }
            } else if (change.mSecurityTokenSerialNo != null) {
                // NOTE: Does this code get executed? Or always handled in internalRestricted?
                if (change.mSecurityTokenSerialNo.length != 16) {
                    log.add(LogType.MSG_MF_ERROR_DIVERT_SERIAL, indent + 1,
                            KeyFormattingUtils.convertKeyIdToHex(change.mKeyId));
                    return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
                }
                log.add(LogType.MSG_MF_KEYTOCARD_FINISH, indent + 1,
                        KeyFormattingUtils.convertKeyIdToHex(change.mKeyId),
                        Hex.toHexString(change.mSecurityTokenSerialNo, 8, 6));
                sKey = PGPSecretKey.constructGnuDummyKey(sKey.getPublicKey(), change.mSecurityTokenSerialNo);
                sKR = PGPSecretKeyRing.insertSecretKey(sKR, sKey);
            }

            // This doesn't concern us any further
            if (!change.mRecertify && (change.mExpiry == null && change.mFlags == null)) {
                continue;
            }

            // expiry must not be in the past
            if (change.mExpiry != null && change.mExpiry != 0
                    && new Date(change.mExpiry * 1000).before(new Date())) {
                log.add(LogType.MSG_MF_ERROR_PAST_EXPIRY, indent + 1,
                        KeyFormattingUtils.convertKeyIdToHex(change.mKeyId));
                return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
            }

            // if this is the master key, update uid certificates instead
            if (change.mKeyId == masterPublicKey.getKeyID()) {
                int flags = change.mFlags == null ? masterKeyFlags : change.mFlags;
                long expiry = change.mExpiry == null ? masterKeyExpiry : change.mExpiry;

                if ((flags & KeyFlags.CERTIFY_OTHER) != KeyFlags.CERTIFY_OTHER) {
                    log.add(LogType.MSG_MF_ERROR_NO_CERTIFY, indent + 1);
                    return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
                }

                PGPPublicKey pKey = updateMasterCertificates(masterSecretKey, masterPrivateKey, masterPublicKey,
                        flags, expiry, cryptoInput, nfcSignOps, indent, log);
                if (pKey == null) {
                    // error log entry has already been added by updateMasterCertificates itself
                    return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
                }
                masterSecretKey = PGPSecretKey.replacePublicKey(sKey, pKey);
                masterPublicKey = pKey;
                sKR = PGPSecretKeyRing.insertSecretKey(sKR, masterSecretKey);
                continue;
            }

            // otherwise, continue working on the public key
            PGPPublicKey pKey = sKey.getPublicKey();

            // keep old flags, or replace with new ones
            int flags = change.mFlags == null ? readKeyFlags(pKey) : change.mFlags;
            long expiry;
            if (change.mExpiry == null) {
                long valid = pKey.getValidSeconds();
                expiry = valid == 0 ? 0 : pKey.getCreationTime().getTime() / 1000 + pKey.getValidSeconds();
            } else {
                expiry = change.mExpiry;
            }

            // drop all old signatures, they will be superseded by the new one
            //noinspection unchecked
            for (PGPSignature sig : new IterableIterator<PGPSignature>(pKey.getSignatures())) {
                // special case: if there is a revocation, don't use expiry from before
                if ((change.mExpiry == null || change.mExpiry == 0L)
                        && sig.getSignatureType() == PGPSignature.SUBKEY_REVOCATION) {
                    expiry = 0;
                }
                pKey = PGPPublicKey.removeCertification(pKey, sig);
            }

            PGPPrivateKey subPrivateKey;
            if (!isDivertToCard(sKey)) {
                PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
                        .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME)
                        .build(cryptoInput.getPassphrase().getCharArray());
                subPrivateKey = sKey.extractPrivateKey(keyDecryptor);
                // super special case: subkey is allowed to sign, but isn't available
                if (subPrivateKey == null) {
                    log.add(LogType.MSG_MF_ERROR_SUB_STRIPPED, indent + 1,
                            KeyFormattingUtils.convertKeyIdToHex(change.mKeyId));
                    return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
                }
            } else {
                subPrivateKey = null;
            }
            try {
                PGPSignature sig = generateSubkeyBindingSignature(
                        getSignatureGenerator(masterSecretKey, cryptoInput), cryptoInput.getSignatureTime(),
                        masterPublicKey, masterPrivateKey, getSignatureGenerator(sKey, cryptoInput),
                        subPrivateKey, pKey, flags, expiry);

                // generate and add new signature
                pKey = PGPPublicKey.addCertification(pKey, sig);
                sKR = PGPSecretKeyRing.insertSecretKey(sKR, PGPSecretKey.replacePublicKey(sKey, pKey));
            } catch (NfcInteractionNeeded e) {
                nfcSignOps.addHash(e.hashToSign, e.hashAlgo);
            }

        }
        subProgressPop();

        // 4b. For each subkey revocation, generate new subkey revocation certificate
        subProgressPush(60, 65);
        for (int i = 0; i < saveParcel.mRevokeSubKeys.size(); i++) {

            progress(R.string.progress_modify_subkeyrevoke, (i - 1) * (100 / saveParcel.mRevokeSubKeys.size()));
            long revocation = saveParcel.mRevokeSubKeys.get(i);
            log.add(LogType.MSG_MF_SUBKEY_REVOKE, indent, KeyFormattingUtils.convertKeyIdToHex(revocation));

            PGPSecretKey sKey = sKR.getSecretKey(revocation);
            if (sKey == null) {
                log.add(LogType.MSG_MF_ERROR_SUBKEY_MISSING, indent + 1,
                        KeyFormattingUtils.convertKeyIdToHex(revocation));
                return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
            }
            PGPPublicKey pKey = sKey.getPublicKey();

            // generate and add new signature
            try {
                PGPSignature sig = generateRevocationSignature(
                        getSignatureGenerator(masterSecretKey, cryptoInput), cryptoInput.getSignatureTime(),
                        masterPublicKey, masterPrivateKey, pKey);

                pKey = PGPPublicKey.addCertification(pKey, sig);
                sKR = PGPSecretKeyRing.insertSecretKey(sKR, PGPSecretKey.replacePublicKey(sKey, pKey));
            } catch (NfcInteractionNeeded e) {
                nfcSignOps.addHash(e.hashToSign, e.hashAlgo);
            }
        }
        subProgressPop();

        // 5. Generate and add new subkeys
        subProgressPush(70, 90);
        for (int i = 0; i < saveParcel.mAddSubKeys.size(); i++) {

            // Check if we were cancelled - again. This operation is expensive so we do it each loop.
            if (checkCancelled()) {
                log.add(LogType.MSG_OPERATION_CANCELLED, indent);
                return new PgpEditKeyResult(PgpEditKeyResult.RESULT_CANCELLED, log, null);
            }

            progress(R.string.progress_modify_subkeyadd, (i - 1) * (100 / saveParcel.mAddSubKeys.size()));
            SaveKeyringParcel.SubkeyAdd add = saveParcel.mAddSubKeys.get(i);
            log.add(LogType.MSG_MF_SUBKEY_NEW, indent,
                    KeyFormattingUtils.getAlgorithmInfo(add.mAlgorithm, add.mKeySize, add.mCurve));

            if (isDivertToCard(masterSecretKey)) {
                log.add(LogType.MSG_MF_ERROR_DIVERT_NEWSUB, indent + 1);
                return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
            }

            if (add.mExpiry == null) {
                log.add(LogType.MSG_MF_ERROR_NULL_EXPIRY, indent + 1);
                return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
            }

            if (add.mExpiry > 0L && new Date(add.mExpiry * 1000).before(new Date())) {
                log.add(LogType.MSG_MF_ERROR_PAST_EXPIRY, indent + 1);
                return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
            }

            // generate a new secret key (privkey only for now)
            subProgressPush((i - 1) * (100 / saveParcel.mAddSubKeys.size()),
                    i * (100 / saveParcel.mAddSubKeys.size()));
            PGPKeyPair keyPair = createKey(add, cryptoInput.getSignatureTime(), log, indent);
            subProgressPop();
            if (keyPair == null) {
                log.add(LogType.MSG_MF_ERROR_PGP, indent + 1);
                return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
            }

            // add subkey binding signature (making this a sub rather than master key)
            PGPPublicKey pKey = keyPair.getPublicKey();
            try {
                PGPSignature cert = generateSubkeyBindingSignature(
                        getSignatureGenerator(masterSecretKey, cryptoInput), cryptoInput.getSignatureTime(),
                        masterPublicKey, masterPrivateKey, getSignatureGenerator(pKey, cryptoInput, false),
                        keyPair.getPrivateKey(), pKey, add.mFlags, add.mExpiry);
                pKey = PGPPublicKey.addSubkeyBindingCertification(pKey, cert);
            } catch (NfcInteractionNeeded e) {
                nfcSignOps.addHash(e.hashToSign, e.hashAlgo);
            }

            PGPSecretKey sKey;
            {
                // Build key encrypter and decrypter based on passphrase
                PGPDigestCalculator encryptorHashCalc = new JcaPGPDigestCalculatorProviderBuilder().build()
                        .get(PgpSecurityConstants.SECRET_KEY_ENCRYPTOR_HASH_ALGO);
                PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder(
                        PgpSecurityConstants.SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO, encryptorHashCalc,
                        PgpSecurityConstants.SECRET_KEY_ENCRYPTOR_S2K_COUNT)
                                .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME)
                                .build(cryptoInput.getPassphrase().getCharArray());

                PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder().build()
                        .get(PgpSecurityConstants.SECRET_KEY_SIGNATURE_CHECKSUM_HASH_ALGO);
                sKey = new PGPSecretKey(keyPair.getPrivateKey(), pKey, sha1Calc, false, keyEncryptor);
            }

            log.add(LogType.MSG_MF_SUBKEY_NEW_ID, indent + 1,
                    KeyFormattingUtils.convertKeyIdToHex(sKey.getKeyID()));

            sKR = PGPSecretKeyRing.insertSecretKey(sKR, sKey);

        }
        subProgressPop();

        // Check if we were cancelled - again. This operation is expensive so we do it each loop.
        if (checkCancelled()) {
            log.add(LogType.MSG_OPERATION_CANCELLED, indent);
            return new PgpEditKeyResult(PgpEditKeyResult.RESULT_CANCELLED, log, null);
        }

        // 6. If requested, change passphrase
        if (saveParcel.getChangeUnlockParcel() != null) {
            progress(R.string.progress_modify_passphrase, 90);
            log.add(LogType.MSG_MF_PASSPHRASE, indent);
            indent += 1;

            sKR = applyNewPassphrase(sKR, masterPublicKey, cryptoInput.getPassphrase(),
                    saveParcel.getChangeUnlockParcel().mNewPassphrase, log, indent);
            if (sKR == null) {
                // The error has been logged above, just return a bad state
                return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
            }

            indent -= 1;
        }

        // 7. if requested, change PIN and/or Admin PIN on security token
        if (saveParcel.mSecurityTokenPin != null) {
            progress(R.string.progress_modify_pin, 90);
            log.add(LogType.MSG_MF_PIN, indent);
            indent += 1;

            nfcKeyToCardOps.setPin(saveParcel.mSecurityTokenPin);

            indent -= 1;
        }
        if (saveParcel.mSecurityTokenAdminPin != null) {
            progress(R.string.progress_modify_admin_pin, 90);
            log.add(LogType.MSG_MF_ADMIN_PIN, indent);
            indent += 1;

            nfcKeyToCardOps.setAdminPin(saveParcel.mSecurityTokenAdminPin);

            indent -= 1;
        }

    } catch (IOException e) {
        Log.e(Constants.TAG, "encountered IOException while modifying key", e);
        log.add(LogType.MSG_MF_ERROR_ENCODE, indent + 1);
        return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
    } catch (PGPException e) {
        Log.e(Constants.TAG, "encountered pgp error while modifying key", e);
        log.add(LogType.MSG_MF_ERROR_PGP, indent + 1);
        return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
    } catch (SignatureException e) {
        Log.e(Constants.TAG, "encountered SignatureException while modifying key", e);
        log.add(LogType.MSG_MF_ERROR_SIG, indent + 1);
        return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
    }

    progress(R.string.progress_done, 100);

    if (!nfcSignOps.isEmpty() && !nfcKeyToCardOps.isEmpty()) {
        log.add(LogType.MSG_MF_ERROR_CONFLICTING_NFC_COMMANDS, indent + 1);
        return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
    }

    if (!nfcSignOps.isEmpty()) {
        log.add(LogType.MSG_MF_REQUIRE_DIVERT, indent);
        return new PgpEditKeyResult(log, nfcSignOps.build(), cryptoInput);
    }

    if (!nfcKeyToCardOps.isEmpty()) {
        log.add(LogType.MSG_MF_REQUIRE_DIVERT, indent);
        return new PgpEditKeyResult(log, nfcKeyToCardOps.build(), cryptoInput);
    }

    log.add(LogType.MSG_MF_SUCCESS, indent);
    return new PgpEditKeyResult(OperationResult.RESULT_OK, log, new UncachedKeyRing(sKR));

}

From source file:org.sufficientlysecure.keychain.pgp.PgpKeyOperation.java

License:Open Source License

/** This method does the actual modifications in a keyring just like internal, except it
 * supports only the subset of operations which require no passphrase, and will error
 * otherwise.//from  ww  w  . j  av  a2s  . c o m
 */
private PgpEditKeyResult internalRestricted(PGPSecretKeyRing sKR, SaveKeyringParcel saveParcel,
        OperationLog log, int indent) {

    progress(R.string.progress_modify, 0);

    // Make sure the saveParcel includes only operations available without passphrase!
    if (!saveParcel.isRestrictedOnly()) {
        log.add(LogType.MSG_MF_ERROR_RESTRICTED, indent);
        return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
    }

    // Check if we were cancelled
    if (checkCancelled()) {
        log.add(LogType.MSG_OPERATION_CANCELLED, indent);
        return new PgpEditKeyResult(PgpEditKeyResult.RESULT_CANCELLED, log, null);
    }

    // The only operation we can do here:
    // 4a. Strip secret keys, or change their protection mode (stripped/divert-to-card)
    subProgressPush(50, 60);
    for (int i = 0; i < saveParcel.mChangeSubKeys.size(); i++) {

        progress(R.string.progress_modify_subkeychange, (i - 1) * (100 / saveParcel.mChangeSubKeys.size()));
        SaveKeyringParcel.SubkeyChange change = saveParcel.mChangeSubKeys.get(i);
        log.add(LogType.MSG_MF_SUBKEY_CHANGE, indent, KeyFormattingUtils.convertKeyIdToHex(change.mKeyId));

        PGPSecretKey sKey = sKR.getSecretKey(change.mKeyId);
        if (sKey == null) {
            log.add(LogType.MSG_MF_ERROR_SUBKEY_MISSING, indent + 1,
                    KeyFormattingUtils.convertKeyIdToHex(change.mKeyId));
            return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
        }

        if (change.mDummyStrip || change.mSecurityTokenSerialNo != null) {
            // IT'S DANGEROUS~
            // no really, it is. this operation irrevocably removes the private key data from the key
            if (change.mDummyStrip) {
                sKey = PGPSecretKey.constructGnuDummyKey(sKey.getPublicKey());
            } else {
                // the serial number must be 16 bytes in length
                if (change.mSecurityTokenSerialNo.length != 16) {
                    log.add(LogType.MSG_MF_ERROR_DIVERT_SERIAL, indent + 1,
                            KeyFormattingUtils.convertKeyIdToHex(change.mKeyId));
                    return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
                }
                log.add(LogType.MSG_MF_KEYTOCARD_FINISH, indent + 1,
                        KeyFormattingUtils.convertKeyIdToHex(change.mKeyId),
                        Hex.toHexString(change.mSecurityTokenSerialNo, 8, 6));
                sKey = PGPSecretKey.constructGnuDummyKey(sKey.getPublicKey(), change.mSecurityTokenSerialNo);
            }
            sKR = PGPSecretKeyRing.insertSecretKey(sKR, sKey);
        }

    }

    // And we're done!
    progress(R.string.progress_done, 100);
    log.add(LogType.MSG_MF_SUCCESS, indent);
    return new PgpEditKeyResult(OperationResult.RESULT_OK, log, new UncachedKeyRing(sKR));

}

From source file:org.sufficientlysecure.keychain.pgp.PgpKeyOperation.java

License:Open Source License

private static PGPSecretKeyRing applyNewPassphrase(PGPSecretKeyRing sKR, PGPPublicKey masterPublicKey,
        Passphrase passphrase, Passphrase newPassphrase, OperationLog log, int indent) throws PGPException {

    PGPDigestCalculator encryptorHashCalc = new JcaPGPDigestCalculatorProviderBuilder().build()
            .get(PgpSecurityConstants.SECRET_KEY_ENCRYPTOR_HASH_ALGO);
    PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
            .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.getCharArray());
    // Build key encryptor based on new passphrase
    PBESecretKeyEncryptor keyEncryptorNew = new JcePBESecretKeyEncryptorBuilder(
            PgpSecurityConstants.SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO, encryptorHashCalc,
            PgpSecurityConstants.SECRET_KEY_ENCRYPTOR_S2K_COUNT)
                    .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(newPassphrase.getCharArray());
    boolean keysModified = false;

    for (PGPSecretKey sKey : new IterableIterator<>(sKR.getSecretKeys())) {
        log.add(LogType.MSG_MF_PASSPHRASE_KEY, indent, KeyFormattingUtils.convertKeyIdToHex(sKey.getKeyID()));

        boolean ok = false;

        try {//w  w w  .  j a v a  2  s.c  o  m
            // try to set new passphrase
            sKey = PGPSecretKey.copyWithNewPassword(sKey, keyDecryptor, keyEncryptorNew);
            ok = true;
        } catch (PGPException e) {

            // if the master key failed && it's not stripped, error!
            if (sKey.getKeyID() == masterPublicKey.getKeyID() && !isDummy(sKey)) {
                log.add(LogType.MSG_MF_ERROR_PASSPHRASE_MASTER, indent + 1);
                return null;
            }

            // being in here means decrypt failed, likely due to a bad passphrase try
            // again with an empty passphrase, maybe we can salvage this
            try {
                log.add(LogType.MSG_MF_PASSPHRASE_EMPTY_RETRY, indent + 1);
                PBESecretKeyDecryptor emptyDecryptor = new JcePBESecretKeyDecryptorBuilder()
                        .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build("".toCharArray());
                sKey = PGPSecretKey.copyWithNewPassword(sKey, emptyDecryptor, keyEncryptorNew);
                ok = true;
            } catch (PGPException e2) {
                // non-fatal but not ok, handled below
            }
        }

        if (!ok) {
            // for a subkey, it's merely a warning
            log.add(LogType.MSG_MF_PASSPHRASE_FAIL, indent + 1,
                    KeyFormattingUtils.convertKeyIdToHex(sKey.getKeyID()));
            continue;
        }

        sKR = PGPSecretKeyRing.insertSecretKey(sKR, sKey);
        keysModified = true;
    }

    if (!keysModified) {
        // no passphrase was changed
        log.add(LogType.MSG_MF_ERROR_PASSPHRASES_UNCHANGED, indent + 1);
        return null;
    }

    return sKR;

}

From source file:org.sufficientlysecure.keychain.pgp.UncachedKeyRing.java

License:Open Source License

/** This operation merges information from a different keyring, returning a combined
 * UncachedKeyRing.//from  w w  w .j av a 2s .  c om
 *
 * The combined keyring contains the subkeys, user ids and user attributes of both input
 * keyrings, but it does not necessarily have the canonicalized property.
 *
 * @param other The UncachedKeyRing to merge. Must not be empty, and of the same masterKeyId
 * @return A consolidated UncachedKeyRing with the data of both input keyrings. Same type as
 * this object, or null on error.
 *
 */
public UncachedKeyRing merge(UncachedKeyRing other, OperationLog log, int indent) {

    // This is logged in the calling method to provide more meta info
    // log.add(isSecret() ? LogType.MSG_MG_SECRET : LogType.MSG_MG_PUBLIC,
    // indent, KeyFormattingUtils.convertKeyIdToHex(getMasterKeyId()));
    indent += 1;

    long masterKeyId = other.getMasterKeyId();

    if (getMasterKeyId() != masterKeyId || !Arrays.equals(getFingerprint(), other.getFingerprint())) {
        log.add(LogType.MSG_MG_ERROR_HETEROGENEOUS, indent);
        return null;
    }

    // remember which certs we already added. this is cheaper than semantic deduplication
    Set<byte[]> certs = new TreeSet<>(new Comparator<byte[]>() {
        public int compare(byte[] left, byte[] right) {
            // check for length equality
            if (left.length != right.length) {
                return left.length - right.length;
            }
            // compare byte-by-byte
            for (int i = 0; i < left.length; i++) {
                if (left[i] != right[i]) {
                    return (left[i] & 0xff) - (right[i] & 0xff);
                }
            }
            // ok they're the same
            return 0;
        }
    });

    try {
        PGPKeyRing result = mRing;
        PGPKeyRing candidate = other.mRing;

        // Pre-load all existing certificates
        for (PGPPublicKey key : new IterableIterator<PGPPublicKey>(result.getPublicKeys())) {
            for (PGPSignature cert : new IterableIterator<PGPSignature>(key.getSignatures())) {
                certs.add(cert.getEncoded());
            }
        }

        // keep track of the number of new certs we add
        int newCerts = 0;

        for (PGPPublicKey key : new IterableIterator<PGPPublicKey>(candidate.getPublicKeys())) {

            final PGPPublicKey resultKey = result.getPublicKey(key.getKeyID());
            if (resultKey == null) {
                log.add(LogType.MSG_MG_NEW_SUBKEY, indent);
                // special case: if both rings are secret, copy over the secret key
                if (isSecret() && other.isSecret()) {
                    PGPSecretKey sKey = ((PGPSecretKeyRing) candidate).getSecretKey(key.getKeyID());
                    result = PGPSecretKeyRing.insertSecretKey((PGPSecretKeyRing) result, sKey);
                } else {
                    // otherwise, just insert the public key
                    result = replacePublicKey(result, key);
                }
                continue;
            }

            // Modifiable version of the old key, which we merge stuff into (keep old for comparison)
            PGPPublicKey modified = resultKey;

            // Iterate certifications
            for (PGPSignature cert : new IterableIterator<PGPSignature>(key.getKeySignatures())) {
                // Don't merge foreign stuff into secret keys
                if (cert.getKeyID() != masterKeyId && isSecret()) {
                    continue;
                }

                byte[] encoded = cert.getEncoded();
                // Known cert, skip it
                if (certs.contains(encoded)) {
                    continue;
                }
                certs.add(encoded);
                modified = PGPPublicKey.addCertification(modified, cert);
                newCerts += 1;
            }

            // If this is a subkey, merge it in and stop here
            if (!key.isMasterKey()) {
                if (modified != resultKey) {
                    result = replacePublicKey(result, modified);
                }
                continue;
            }

            // Copy over all user id certificates
            for (byte[] rawUserId : new IterableIterator<byte[]>(key.getRawUserIDs())) {
                @SuppressWarnings("unchecked")
                Iterator<PGPSignature> signaturesIt = key.getSignaturesForID(rawUserId);
                // no signatures for this User ID, skip it
                if (signaturesIt == null) {
                    continue;
                }
                for (PGPSignature cert : new IterableIterator<>(signaturesIt)) {
                    // Don't merge foreign stuff into secret keys
                    if (cert.getKeyID() != masterKeyId && isSecret()) {
                        continue;
                    }
                    byte[] encoded = cert.getEncoded();
                    // Known cert, skip it
                    if (certs.contains(encoded)) {
                        continue;
                    }
                    newCerts += 1;
                    certs.add(encoded);
                    modified = PGPPublicKey.addCertification(modified, rawUserId, cert);
                }
            }

            // Copy over all user attribute certificates
            for (PGPUserAttributeSubpacketVector vector : new IterableIterator<PGPUserAttributeSubpacketVector>(
                    key.getUserAttributes())) {
                @SuppressWarnings("unchecked")
                Iterator<PGPSignature> signaturesIt = key.getSignaturesForUserAttribute(vector);
                // no signatures for this user attribute attribute, skip it
                if (signaturesIt == null) {
                    continue;
                }
                for (PGPSignature cert : new IterableIterator<>(signaturesIt)) {
                    // Don't merge foreign stuff into secret keys
                    if (cert.getKeyID() != masterKeyId && isSecret()) {
                        continue;
                    }
                    byte[] encoded = cert.getEncoded();
                    // Known cert, skip it
                    if (certs.contains(encoded)) {
                        continue;
                    }
                    newCerts += 1;
                    certs.add(encoded);
                    modified = PGPPublicKey.addCertification(modified, vector, cert);
                }
            }

            // If anything change, save the updated (sub)key
            if (modified != resultKey) {
                result = replacePublicKey(result, modified);
            }

        }

        if (newCerts > 0) {
            log.add(LogType.MSG_MG_FOUND_NEW, indent, Integer.toString(newCerts));
        } else {
            log.add(LogType.MSG_MG_UNCHANGED, indent);
        }

        return new UncachedKeyRing(result);

    } catch (IOException e) {
        log.add(LogType.MSG_MG_ERROR_ENCODE, indent);
        return null;
    }

}

From source file:org.sufficientlysecure.keychain.pgp.UncachedKeyRing.java

License:Open Source License

/** This method replaces a public key in a keyring.
 *
 * This method essentially wraps PGP*KeyRing.insertPublicKey, where the keyring may be of either
 * the secret or public subclass.//  w ww  .j  a  va  2 s .c  o  m
 *
 * @return the resulting PGPKeyRing of the same type as the input
 */
private static PGPKeyRing replacePublicKey(PGPKeyRing ring, PGPPublicKey key) {
    if (ring instanceof PGPPublicKeyRing) {
        PGPPublicKeyRing pubRing = (PGPPublicKeyRing) ring;
        return PGPPublicKeyRing.insertPublicKey(pubRing, key);
    } else {
        PGPSecretKeyRing secRing = (PGPSecretKeyRing) ring;
        PGPSecretKey sKey = secRing.getSecretKey(key.getKeyID());
        // if this is a secret key which does not yet occur in the secret ring
        if (sKey == null) {
            // generate a stripped secret (sub)key
            sKey = PGPSecretKey.constructGnuDummyKey(key);
        }
        sKey = PGPSecretKey.replacePublicKey(sKey, key);
        return PGPSecretKeyRing.insertSecretKey(secRing, sKey);
    }
}

From source file:org.sufficientlysecure.keychain.pgp.UncachedKeyRing.java

License:Open Source License

@VisibleForTesting
public static UncachedKeyRing forTestingOnlyAddDummyLocalSignature(UncachedKeyRing uncachedKeyRing,
        String passphrase) throws Exception {
    PGPSecretKeyRing sKR = (PGPSecretKeyRing) uncachedKeyRing.mRing;

    PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
            .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray());
    PGPPrivateKey masterPrivateKey = sKR.getSecretKey().extractPrivateKey(keyDecryptor);
    PGPPublicKey masterPublicKey = uncachedKeyRing.mRing.getPublicKey();

    // add packet with "pin" notation data
    PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
            masterPrivateKey.getPublicKeyPacket().getAlgorithm(),
            PgpSecurityConstants.SECRET_KEY_BINDING_SIGNATURE_HASH_ALGO)
                    .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
    PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
    { // set subpackets
        PGPSignatureSubpacketGenerator hashedPacketsGen = new PGPSignatureSubpacketGenerator();
        hashedPacketsGen.setExportable(false, false);
        hashedPacketsGen.setNotationData(false, true, "dummynotationdata", "some data");
        sGen.setHashedSubpackets(hashedPacketsGen.generate());
    }//from  ww  w . j a  v  a 2 s  .c  o  m
    sGen.init(PGPSignature.DIRECT_KEY, masterPrivateKey);
    PGPSignature emptySig = sGen.generateCertification(masterPublicKey);

    masterPublicKey = PGPPublicKey.addCertification(masterPublicKey, emptySig);
    sKR = PGPSecretKeyRing.insertSecretKey(sKR,
            PGPSecretKey.replacePublicKey(sKR.getSecretKey(), masterPublicKey));

    return new UncachedKeyRing(sKR);
}