Example usage for org.bouncycastle.openpgp.operator.jcajce JcePBESecretKeyEncryptorBuilder JcePBESecretKeyEncryptorBuilder

List of usage examples for org.bouncycastle.openpgp.operator.jcajce JcePBESecretKeyEncryptorBuilder JcePBESecretKeyEncryptorBuilder

Introduction

In this page you can find the example usage for org.bouncycastle.openpgp.operator.jcajce JcePBESecretKeyEncryptorBuilder JcePBESecretKeyEncryptorBuilder.

Prototype

public JcePBESecretKeyEncryptorBuilder(int encAlgorithm, PGPDigestCalculator s2kDigestCalculator,
        int s2kCount) 

Source Link

Document

Create an SecretKeyEncryptorBuilder with the S2k count different to the default of 0x60, and the S2K digest different from SHA-1.

Usage

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

License:Open Source License

public PgpEditKeyResult createSecretKeyRing(SaveKeyringParcel saveParcel) {

    OperationLog log = new OperationLog();
    int indent = 0;

    try {//from  w  w  w  .  j a v a  2 s.c  o  m

        log.add(LogType.MSG_CR, indent);
        progress(R.string.progress_building_key, 0);
        indent += 1;

        if (saveParcel.mAddSubKeys.isEmpty()) {
            log.add(LogType.MSG_CR_ERROR_NO_MASTER, indent);
            return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
        }

        if (saveParcel.mAddUserIds.isEmpty()) {
            log.add(LogType.MSG_CR_ERROR_NO_USER_ID, indent);
            return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
        }

        SubkeyAdd add = saveParcel.mAddSubKeys.remove(0);
        if ((add.mFlags & KeyFlags.CERTIFY_OTHER) != KeyFlags.CERTIFY_OTHER) {
            log.add(LogType.MSG_CR_ERROR_NO_CERTIFY, indent);
            return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
        }

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

        Date creationTime = new Date();

        subProgressPush(10, 30);
        PGPKeyPair keyPair = createKey(add, creationTime, log, indent);
        subProgressPop();

        // return null if this failed (an error will already have been logged by createKey)
        if (keyPair == null) {
            return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
        }

        progress(R.string.progress_building_master_key, 40);

        // 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("".toCharArray());

        PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder().build()
                .get(PgpSecurityConstants.SECRET_KEY_SIGNATURE_CHECKSUM_HASH_ALGO);
        PGPSecretKey masterSecretKey = new PGPSecretKey(keyPair.getPrivateKey(), keyPair.getPublicKey(),
                sha1Calc, true, keyEncryptor);

        PGPSecretKeyRing sKR = new PGPSecretKeyRing(masterSecretKey.getEncoded(),
                new JcaKeyFingerprintCalculator());

        subProgressPush(50, 100);
        CryptoInputParcel cryptoInput = new CryptoInputParcel(creationTime, new Passphrase(""));
        return internal(sKR, masterSecretKey, add.mFlags, add.mExpiry, cryptoInput, saveParcel, log, indent);

    } catch (PGPException e) {
        log.add(LogType.MSG_CR_ERROR_INTERNAL_PGP, indent);
        Log.e(Constants.TAG, "pgp error encoding key", e);
        return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
    } catch (IOException e) {
        Log.e(Constants.TAG, "io error encoding key", e);
        return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
    }

}

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;/*from   w w w  . jav a2s .  c  o m*/

    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

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 ww . ja  v  a2  s . co  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.UncachedKeyringCanonicalizeTest.java

License:Open Source License

@Test
public void testDuplicateSubkey() throws Exception {

    { // duplicate subkey

        // get subkey packets
        Iterator<RawPacket> it = KeyringTestingHelper.parseKeyring(ring.getEncoded());
        RawPacket subKey = KeyringTestingHelper.getNth(it, 7);
        RawPacket subSig = it.next();//from   ww  w. j  av  a 2s. com

        // inject at a second position
        UncachedKeyRing modified = ring;
        modified = KeyringTestingHelper.injectPacket(modified, subKey.buf, 9);
        modified = KeyringTestingHelper.injectPacket(modified, subSig.buf, 10);

        // canonicalize, and check if we lose the bad signature
        OperationLog log = new OperationLog();
        CanonicalizedKeyRing canonicalized = modified.canonicalize(log, 0);
        Assert.assertNull("canonicalization with duplicate subkey should fail", canonicalized);
        Assert.assertTrue("log should contain dup_key event", log.containsType(LogType.MSG_KC_ERROR_DUP_KEY));
    }

    { // duplicate subkey, which is the same as the master key

        // We actually encountered one of these in the wild:
        // https://www.sparkasse-holstein.de/firmenkunden/electronic_banking/secure-e-mail/pdf/Spk_Holstein_PGP_Domain-Zertifikat.asc

        CanonicalizedSecretKeyRing canonicalized = (CanonicalizedSecretKeyRing) ring.canonicalize(log, 0);

        CanonicalizedSecretKey masterSecretKey = canonicalized.getSecretKey();
        masterSecretKey.unlock(new Passphrase());
        PGPPublicKey masterPublicKey = masterSecretKey.getPublicKey();
        CryptoInputParcel cryptoInput = new CryptoInputParcel(new Date());
        PGPSignature cert = PgpKeyOperation.generateSubkeyBindingSignature(
                PgpKeyOperation.getSignatureGenerator(masterSecretKey.getSecretKey(), cryptoInput),
                cryptoInput.getSignatureTime(), masterPublicKey, masterSecretKey.getPrivateKey(),
                PgpKeyOperation.getSignatureGenerator(masterSecretKey.getSecretKey(), null),
                masterSecretKey.getPrivateKey(), masterPublicKey, masterSecretKey.getKeyUsage(), 0);
        PGPPublicKey subPubKey = PGPPublicKey.addSubkeyBindingCertification(masterPublicKey, cert);

        PGPSecretKey sKey;
        {
            // Build key encrypter and decrypter based on passphrase
            PGPDigestCalculator encryptorHashCalc = new JcaPGPDigestCalculatorProviderBuilder().build()
                    .get(HashAlgorithmTags.SHA256);
            PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder(
                    SymmetricKeyAlgorithmTags.AES_256, encryptorHashCalc, 10)
                            .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build("".toCharArray());

            // NOTE: only SHA1 is supported for key checksum calculations.
            PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder().build()
                    .get(HashAlgorithmTags.SHA1);
            sKey = new PGPSecretKey(masterSecretKey.getPrivateKey(), subPubKey, sha1Calc, false, keyEncryptor);
        }

        UncachedKeyRing modified = KeyringTestingHelper.injectPacket(ring, sKey.getEncoded(), 7);

        // canonicalize, and check if we lose the bad signature
        OperationLog log = new OperationLog();
        CanonicalizedKeyRing result = modified.canonicalize(log, 0);
        Assert.assertNull("canonicalization with duplicate subkey (from master) should fail", result);
        Assert.assertTrue("log should contain dup_key event", log.containsType(LogType.MSG_KC_ERROR_DUP_KEY));
    }

}