简体   繁体   中英

Encryption using multiple RSA public keys

I'm writing module for server which will send e-mails. In client application user can add many receipients and each of them has its own public key. I want to encrypt attachments using multiple keys. For example if I add 3 receipients then attachments should be encrypted with 3 different public keys. I'm using bouncy castle to do that but it works only for the first public key in encryption process. I mean thath only the first person can decrypt using its own private key, for the rest it doesn't work. My code for adding methods for each key looks like:

PGPEncryptedDataGenerator encryptedDataGenerator = new PGPEncryptedDataGenerator(dataEncryptor);

for (PGPPublicKey publicKey : publicKeys) {
        encryptedDataGenerator.addMethod(new BcPublicKeyKeyEncryptionMethodGenerator(publicKey));
}

Whole method looks like:

public File encryptFile(String fileName,
        boolean armor,
        boolean withIntegrityCheck) throws IOException,
        NoSuchProviderException,
        PGPException {
    Security.addProvider(new BouncyCastleProvider());

    ByteArrayOutputStream bOut = new ByteArrayOutputStream();

    PGPCompressedDataGenerator comData
            = new PGPCompressedDataGenerator(PGPCompressedData.UNCOMPRESSED);

    PGPUtil.writeFileToLiteralData(comData.open(bOut),
            PGPLiteralData.BINARY,
            new File(fileName));

    comData.close();

    BcPGPDataEncryptorBuilder dataEncryptor
            = new BcPGPDataEncryptorBuilder(PGPEncryptedData.AES_256);

    dataEncryptor.setWithIntegrityPacket(withIntegrityCheck);

    dataEncryptor.setSecureRandom(new SecureRandom());

    PGPEncryptedDataGenerator encryptedDataGenerator
            = new PGPEncryptedDataGenerator(dataEncryptor);

    for (PGPPublicKey publicKey : publicKeys) {
        encryptedDataGenerator.addMethod(new BcPublicKeyKeyEncryptionMethodGenerator(publicKey));
    }

    byte[] bytes = bOut.toByteArray();

    FileOutputStream localByteArrayOutputStream = new FileOutputStream(fileName);

    Object localObject = localByteArrayOutputStream;

    if (armor) {

        localObject = new ArmoredOutputStream((OutputStream) localObject);

    }

    OutputStream localOutputStream = encryptedDataGenerator.open((OutputStream) localObject,
            bytes.length);

    localOutputStream.write(bytes);

    localOutputStream.close();

    return new File(fileName);
}

Can someone help me and tell me what I'm doing wrong?

Thank you for every help.

[EDIT] This code works, I had problem in method loading multiple keys.

Well, I had the same problem a year later. I wish that you've solved yours. I'm writing my solution here just in case that someone else has similar issues.

Your encryption code doesn't have problem. The problem might be in the decryption. For an encrypted data object, the correct key should be found by using the key id stored with the object. My decryption process reads like the following:

private byte[] decryptWithKey(byte[] bytes, PGPSecretKey secKey, String pass)
        throws PGPException, IOException {
    PBESecretKeyDecryptor keyDec = new JcePBESecretKeyDecryptorBuilder(
            new JcaPGPDigestCalculatorProviderBuilder().setProvider("BC").build())
            .setProvider("BC").build(pass.toCharArray());
    ByteArrayOutputStream bout = new ByteArrayOutputStream();

    PGPPrivateKey privateKey = secKey.extractPrivateKey(keyDec);
    PublicKeyDataDecryptorFactory dec1 =
            new JcePublicKeyDataDecryptorFactoryBuilder().setProvider("BC").build(privateKey);
    JcaPGPObjectFactory objFact = new JcaPGPObjectFactory(bytes);
    PGPEncryptedDataList encList = (PGPEncryptedDataList) objFact.nextObject();

    PGPPublicKeyEncryptedData encD = null;
    for(Iterator<PGPPublicKeyEncryptedData> it = encList.iterator(); it.hasNext(); ) {
        PGPPublicKeyEncryptedData end = it.next();
        if (secKey.getKeyID() == end.getKeyID()) {
            encD = end;
            break;
        }
    }
    assert encD != null: "Cannot find encrypted data with key: "
            + Long.toHexString(secKey.getKeyID());
    InputStream in = encD.getDataStream(dec1);
    byte[] buf = new byte[BufferSize];
    for (int len; (len = in.read(buf)) >= 0; ) {
        bout.write(buf, 0, len);
    }
    bout.close();
    return bout.toByteArray();
}

The key is the for loop that finds the matching key for the encrypted object.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM