Bouncy Castle 加密的有效载荷从 SAP PI 中被破坏

Bouncy Castle-encrypted payload comes broken from SAP PI

问题

我正在使用 Bouncy Castle java 通过 PGP 加密文件。该程序旨在 运行 进入 SAP PI 7.0。当我 运行 PI 针对解密程序的输出(加密文件)时,我得到一个 空的解密文件 ,没有错误。

因此,我尝试使用相同的参数在 Eclipse 中加密相同的源文件。这一次,我能够正确解密输出以 检索我的原始文件 。相同的代码,相同的输入。

在某些时候,我注意到 PI 输出比 Eclipse 的输出短几个字节(通常是 32 个字节)。我认为这就是解密输出为空而没有错误的原因。我不知道加密文件中可能缺少什么,因为两个 PGP 消息具有相同的形状。

关于如何修复它有什么建议吗?是否缺少 PGP 消息的一部分?我是否错过了 PI 环境中的库或配置点?

技术细节

充气城堡

本地环境

SAP PI 环境

DSA 密钥对

Public键

-----BEGIN PGP PUBLIC KEY BLOCK-----

Version: BCPG v1.47

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

=CPWK

-----END PGP PUBLIC KEY BLOCK-----

私钥(密码:“TestPass12345!”)

-----BEGIN PGP PRIVATE KEY BLOCK-----

Version: BCPG v1.47

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

=kuac

-----END PGP PRIVATE KEY BLOCK-----

加密输出

日食

-----BEGIN PGP MESSAGE-----

Version: BCPG v1.47

hQQOA0fjQmjVGrtrEA/+JTCsjY1frycHtMDeTPYfmsRX/nnVuTTvB2c9ZkK3GJq+ TF2kMXhG4xj8XO5c7DtIehKwIAMvvirpX456mnObGMUQMtguXvsCMuY766SmgRx6 GebHU0v166xkN/9ZmHBsQxti7P1qFAJe4XVAhNXb+odUGrnSPNfQY4gUvvP6DM7a azaCQygElNfhBP26XODKD8h2xJqyNF9HodEmVevrhvBPQFZvAcA0KLFX1hvWG9Us D4eOrZp0UL4KoabDtHcTvUILRqmgslX9oMMrEoPdEdkvWJTeZMf8Yf8S0aNoUtAB Rpi49n2kTiQcX5x313stxSaP9mcmyKsMAlXn0BgnWUS/w4GGGB6GWki1OirHi2DG 3Q0LOMWlYrLinXq9C+3cHCSiBYhF6Z+D74L97YGNMtHPfZ6B/Q4B7B64RKJlmC/S 7k0aeyGSzYm35heBKifKs6gQiiW352HppJsOvgsZr+0/p8BIMZtgJReFnZ/plsz0 vB3aoDYkUtNJR+WpwRYUnS4YR7Ga5/uqQvrFUBuyvOQdfsZJeLxzG6geyefBi183 GskEMOWHTdU5uUgI2LGzCpp1hOJ5+O/KXdLUIF+r+Z/khp+qsJPVmxRRhAFuf0Uq 4outUwiq/cr0PJ9je3rcIpx6jku2FFzlf3CH6rVVrqU8jzHJOtrq5yKMsVLIJeQQ AIUTlgkgXFzcl6P1fuo73uZBY047twIq1pe7rW2rKZW7V5eZNM+FPgBjZ0NFu19A Ca9U5EobdNO2ZZxD4+ye+GKtGdKmQ6I3+B938tVnJYvRZwoc7oyKieO59oxuJGgG UkIx34ivVojvovpk5mojGL0Ne1RPV3mP+88r/EHmEuyVYiwj6zN5TP6WecEBBxAY EIJKae+GfArAW9fjIq+FRTNU6W3F5dhp3AasbUpIcS07exOzIy6zmhyUYchEFRWW /tKQzXT42zZySPicVI5NkepOvCwRIaTU/VYL12bMN26bvbZRXYoONxbOXjywOCy8 Xf9Shr/Uf9PUc9P3H0rCflHxCe+KeVya3FDNhIJzyOkE0LAR3BXIdidSV64UBrkN FBYZv4CAqzI5pyuGoK0Jfc5sCLVtPY06s9n/EocNQUmbRXCgOKv1dV9KSTByyR4J j3wQ8Vh/iIPYiP352VSsql2IrYHPHaNT12BrgD1wu9ZD3+GKV33nbEiyPnsVbMLN 6PuMS7DnDyqQQIt5j5eg2sM3t9UTs938DDIFDp1hCVY6YBvPRgMCB4Gni54yxfc8 QKn++90yWR6Fu0pwnsD2WL6Pcqf3xD5r+ke+HG8FmYo8OwIkyLbHLCyacMvs6dhK ZZnlFNvRteSLD1hw0o+MF6RoC9hhJYwOlfWGOBqEMjYf0lkB3O1rt6maKwNG1ljt kG3lN0xRK5XMFPMmzlZfI2xj4vMLlN+06uNnir9QSWqszOL1aPhR511vr2bGj/Zx +eSizjofZbU0p3wiR8D60s+9PeuE24XbOfsyCg==

=/OMU

-----END PGP MESSAGE-----

SAP PI

-----BEGIN PGP MESSAGE-----

Version: BCPG v1.47

hQQOA0fjQmjVGrtrEBAAh/d/hO+no+nonMzRJlLVnJeEcahzDTtCD9+aIljOsLIu pUgyJ1VZTGe6heqJw4R88V96Yc1BxsW0SkvcNyZ5HCraRyt1yeNQE4e6BgFI7J53 nBBb1d8Qd07YIRpiOgqaVDgluLa7LXkFPjgmN2JEPXUSchtI73EEFYIxmeSwdyyY wKRi3kjcZu/MK9NJ74InWviFVQBumpyq9o4SdEViyrp8s/K3O2knzsV1es1as5yL Fdh4O0Rf8klWv8tb4hYdtGjtvpuETQoYP5vaXgWGqajkvfV++IaYD2FPh4ENF9om 3jG+GoAwPNzaxe5RCJResIXuYj0wTig3S8xsJiLmrZC7/bMb8/JmhstoCv7192h3 jUg/Ao1Y5iwbp8GYx7h+DQuW81MuXJpaCXPfWSWnHinkqS0SC25v13i7YBSrKUYp tN75WAiX1zLZKAqseS/OIz9luRaxtpL8Ke4u9EWD7ywwSXuOoeNdSnl4Rl5RQ+9P qrNPjlMdoIZTw4h69TIJvbe9og0izgeI+1Jmu0B7B8d/afkn2qKN8e/Vz7wcSPs6 tzS7U3yRuAW4wgExZATnNJXINIjuBX/tsvenWqhgofNOSY9wynZgYUUxBL2vzia3 o9wWE8J5GI7uTsQzrWrDcuzwV9fZWVbeWKj6lO6p7pn8yvJlZPhsQPyhHAqBOBsP /2DLYjhIOcGi4CnqfVCvf8FZqqjPquol081rRCXaA2A9Q6rlMH1OcqTOBLjt78RL uw8t2YtNxJX3uxsb9jVSznBBltN283ZLPO9IJERXffT+BL86S8hmhLXSkhQPmnRt ijYx6cAJNizLtzJzgrGbjL7o4s3Q8+QFF2rqL3GcdySzdxM61lwVGYJ1MFyJqBCN ibLbz3u+8wovZ5F/0kOt54X4bG7YF31UrlcFam8b4cpHa3vdKJXRfXRwGD82PCWo HDn33MeIkYOdQtBNDkNMl2DF6GcAaD2Z6R4FlS/h+ywW6HggD1OhKPiCu/xn8Ojy WWR3kLiqia0Tdz7dlBFBHxcNQM+1NtiZ9HAU+D71Evyx3R/ezBUrDiHnnZSujk1E Pvh1l5DH0vN788VwDOBjKZRVx7Y7xlWl/oO6wlpLZ/SK0XN+x3jjeReDjnD7FPU/ RtBddqgbfMap80VQ+5QXXG4zaJKrkSj3jW4zW+W4+msbMfS5MGzkFLkIHh9i5WCI JYsD31JQOb+rTr/UlCJWBdIC9FSlIKlvMPpHmBB+v853O/SYaBm3Gme3or/xB5y9 Y58vK3M9bI9848qkivG2Q2XO+B4URSOTr8GTh8qZKDOYQ12kaWhC3Gc7rxM+N04c 6itSVNMX9ohUgLMidLShx5HcWPcdnb396nQCtP0gyDS30ksB6AJzvhVaNTlcyGYy byswfn5fLq+AAI5vBdDiUFjTOX051y/jDKG1B26txgQLo0gCHiQnYYhtHQXe2kev wGSuO2+0v41e9EachmU=

=OL09

-----END PGP MESSAGE-----

Java代码

BcPGP.java

public class BcPGP {

    private static final int BUFFER_SIZE = 1 << 16; // should always be power of
                                                    // 2
    private static final int KEY_FLAGS = 27;
    private static final int[] MASTER_KEY_CERTIFICATION_TYPES = new int[] { PGPSignature.POSITIVE_CERTIFICATION,
            PGPSignature.CASUAL_CERTIFICATION, PGPSignature.NO_CERTIFICATION, PGPSignature.DEFAULT_CERTIFICATION };

    public static PGPPublicKey readPublicKey(InputStream in) throws IOException, PGPException {

        PGPPublicKeyRingCollection keyRingCollection = new PGPPublicKeyRingCollection(PGPUtil.getDecoderStream(in));

        //
        // we just loop through the collection till we find a key suitable for
        // encryption, in the real
        // world you would probably want to be a bit smarter about this.
        //
        PGPPublicKey publicKey = null;

        //
        // iterate through the key rings.
        //
        Iterator rIt = keyRingCollection.getKeyRings();

        while (publicKey == null && rIt.hasNext()) {
            PGPPublicKeyRing kRing = (PGPPublicKeyRing) rIt.next();
            Iterator kIt = kRing.getPublicKeys();
            while (publicKey == null && kIt.hasNext()) {
                PGPPublicKey key = (PGPPublicKey) kIt.next();
                if (key.isEncryptionKey()) {
                    publicKey = key;
                }
            }
        }

        if (publicKey == null) {
            throw new IllegalArgumentException("Can't find public key in the key ring.");
        }
        if (!isForEncryption(publicKey)) {
            throw new IllegalArgumentException("KeyID " + publicKey.getKeyID() + " not flagged for encryption.");
        }

        return publicKey;
    }

    public static PGPSecretKey readSecretKey(InputStream in) throws IOException, PGPException {

        PGPSecretKeyRingCollection keyRingCollection = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(in));

        //
        // We just loop through the collection till we find a key suitable for
        // signing.
        // In the real world you would probably want to be a bit smarter about
        // this.
        //
        PGPSecretKey secretKey = null;

        Iterator rIt = keyRingCollection.getKeyRings();
        while (secretKey == null && rIt.hasNext()) {
            PGPSecretKeyRing keyRing = (PGPSecretKeyRing) rIt.next();
            Iterator kIt = keyRing.getSecretKeys();
            while (secretKey == null && kIt.hasNext()) {
                PGPSecretKey key = (PGPSecretKey) kIt.next();
                if (key.isSigningKey()) {
                    secretKey = key;
                }
            }
        }

        // Validate secret key
        if (secretKey == null) {
            throw new IllegalArgumentException("Can't find private key in the key ring.");
        }
        if (!secretKey.isSigningKey()) {
            throw new IllegalArgumentException("Private key does not allow signing.");
        }
        if (secretKey.getPublicKey().isRevoked()) {
            throw new IllegalArgumentException("Private key has been revoked.");
        }
        if (!hasKeyFlags(secretKey.getPublicKey(), KeyFlags.SIGN_DATA)) {
            throw new IllegalArgumentException("Key cannot be used for signing.");
        }

        return secretKey;
    }

    /**
     * Load a secret key ring collection from keyIn and find the private key
     * corresponding to keyID if it exists.
     *
     * @param keyIn
     *            input stream representing a key ring collection.
     * @param keyID
     *            keyID we want.
     * @param pass
     *            passphrase to decrypt secret key with.
     * @return
     * @throws IOException
     * @throws PGPException
     * @throws NoSuchProviderException
     */
    public static PGPPrivateKey findPrivateKey(InputStream keyIn, long keyID, char[] pass) throws IOException, PGPException,
            NoSuchProviderException {
        PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(keyIn));
        return findPrivateKey(pgpSec.getSecretKey(keyID), pass);

    }

    /**
     * Load a secret key and find the private key in it
     * 
     * @param pgpSecKey
     *            The secret key
     * @param pass
     *            passphrase to decrypt secret key with
     * @return
     * @throws PGPException
     */
    public static PGPPrivateKey findPrivateKey(PGPSecretKey pgpSecKey, char[] pass) throws PGPException {
        if (pgpSecKey == null)
            return null;

        PBESecretKeyDecryptor decryptor = new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(pass);
        return pgpSecKey.extractPrivateKey(decryptor);
    }

    /**
     * decrypt the passed in message stream
     */
    public static void decryptFile(InputStream in, OutputStream out, InputStream keyIn, char[] passwd) throws Exception {
        Security.addProvider(new BouncyCastleProvider());

        in = org.bouncycastle.openpgp.PGPUtil.getDecoderStream(in);

        PGPObjectFactory pgpF = new PGPObjectFactory(in);
        PGPEncryptedDataList enc;

        Object o = pgpF.nextObject();
        //
        // the first object might be a PGP marker packet.
        //
        if (o instanceof PGPEncryptedDataList) {
            enc = (PGPEncryptedDataList) o;
        } else {
            enc = (PGPEncryptedDataList) pgpF.nextObject();
        }

        //
        // find the secret key
        //
        Iterator it = enc.getEncryptedDataObjects();
        PGPPrivateKey sKey = null;
        PGPPublicKeyEncryptedData pbe = null;

        while (sKey == null && it.hasNext()) {
            pbe = (PGPPublicKeyEncryptedData) it.next();

            sKey = findPrivateKey(keyIn, pbe.getKeyID(), passwd);
        }

        if (sKey == null) {
            throw new IllegalArgumentException("Secret key for message not found.");
        }

        InputStream clear = pbe.getDataStream(new BcPublicKeyDataDecryptorFactory(sKey));

        PGPObjectFactory plainFact = new PGPObjectFactory(clear);

        Object message = plainFact.nextObject();

        if (message instanceof PGPCompressedData) {
            PGPCompressedData cData = (PGPCompressedData) message;
            PGPObjectFactory pgpFact = new PGPObjectFactory(cData.getDataStream());

            message = pgpFact.nextObject();
        }

        if (message instanceof PGPLiteralData) {
            PGPLiteralData ld = (PGPLiteralData) message;

            InputStream unc = ld.getInputStream();
            int ch;

            while ((ch = unc.read()) >= 0) {
                out.write(ch);
            }
        } else if (message instanceof PGPOnePassSignatureList) {
            throw new PGPException("Encrypted message contains a signed message - not literal data.");
        } else {
            throw new PGPException("Message is not a simple encrypted file - type unknown.");
        }

        if (pbe.isIntegrityProtected()) {
            if (!pbe.verify()) {
                throw new PGPException("Message failed integrity check");
            }
        }
    }

    public static void encryptFile(OutputStream out, InputStream is, PGPPublicKey encKey, boolean armor,
            boolean withIntegrityCheck, int compressType, int encryptType) throws IOException, NoSuchProviderException,
            PGPException {
        System.out.println("Add BouncyCastleProvider");
        Security.addProvider(new BouncyCastleProvider());

        if (armor) {
            out = new ArmoredOutputStream(out);
        }

        ByteArrayOutputStream bOut = new ByteArrayOutputStream();
        PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator(compressType);

        // setup temp file to hold source data - this is necessary when using
        // PGPUtil.writeFileToLiteralData which uses a file
        System.out.println("Creating a temp file...");
        File tempfile = File.createTempFile("pgp", null);
        FileOutputStream fos = new FileOutputStream(tempfile);
        int read = 0;
        byte[] inBytes = new byte[1024];
        while ((read = is.read(inBytes)) != -1) {
            fos.write(inBytes, 0, read);
        }
        fos.flush();
        fos.close();
        System.out.println("Temp file created at ");
        System.out.println(tempfile.getAbsolutePath());

        PGPUtil.writeFileToLiteralData(comData.open(bOut), PGPLiteralData.BINARY, new File(tempfile.getAbsolutePath()));
        comData.close();

        BcPGPDataEncryptorBuilder dataEncryptor = new BcPGPDataEncryptorBuilder(encryptType);
        dataEncryptor.setWithIntegrityPacket(withIntegrityCheck);
        dataEncryptor.setSecureRandom(new SecureRandom());

        PGPEncryptedDataGenerator encryptedDataGenerator = new PGPEncryptedDataGenerator(dataEncryptor);
        encryptedDataGenerator.addMethod(new BcPublicKeyKeyEncryptionMethodGenerator(encKey));

        byte[] outBytes = bOut.toByteArray();
        OutputStream cOut = encryptedDataGenerator.open(out, outBytes.length);
        cOut.write(outBytes);
        cOut.close();
        out.close();
        System.out.println("data encrypted");
    }

    public static void signEncryptFile(OutputStream out, String fileName, PGPPublicKey publicKey, PGPSecretKey secretKey,
            String password, boolean armor, boolean withIntegrityCheck) throws Exception {

        // Initialize Bouncy Castle security provider
        Provider provider = new BouncyCastleProvider();
        Security.addProvider(provider);

        if (armor) {
            out = new ArmoredOutputStream(out);
        }

        BcPGPDataEncryptorBuilder dataEncryptor = new BcPGPDataEncryptorBuilder(SymmetricKeyAlgorithmTags.TRIPLE_DES);
        dataEncryptor.setWithIntegrityPacket(withIntegrityCheck);
        dataEncryptor.setSecureRandom(new SecureRandom());

        PGPEncryptedDataGenerator encryptedDataGenerator = new PGPEncryptedDataGenerator(dataEncryptor);
        encryptedDataGenerator.addMethod(new BcPublicKeyKeyEncryptionMethodGenerator(publicKey));

        OutputStream encryptedOut = encryptedDataGenerator.open(out, new byte[BcPGP.BUFFER_SIZE]);

        // Initialize compressed data generator
        PGPCompressedDataGenerator compressedDataGenerator = new PGPCompressedDataGenerator(CompressionAlgorithmTags.ZIP);
        OutputStream compressedOut = compressedDataGenerator.open(encryptedOut, new byte[BcPGP.BUFFER_SIZE]);

        // Initialize signature generator
        PGPPrivateKey privateKey = findPrivateKey(secretKey, password.toCharArray());

        PGPContentSignerBuilder signerBuilder = new BcPGPContentSignerBuilder(secretKey.getPublicKey().getAlgorithm(),
                HashAlgorithmTags.SHA1);

        PGPSignatureGenerator signatureGenerator = new PGPSignatureGenerator(signerBuilder);
        signatureGenerator.init(PGPSignature.BINARY_DOCUMENT, privateKey);

        boolean firstTime = true;
        Iterator it = secretKey.getPublicKey().getUserIDs();
        while (it.hasNext() && firstTime) {
            PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
            spGen.setSignerUserID(false, (String) it.next());
            signatureGenerator.setHashedSubpackets(spGen.generate());
            // Exit the loop after the first iteration
            firstTime = false;
        }
        signatureGenerator.generateOnePassVersion(false).encode(compressedOut);

        // Initialize literal data generator
        PGPLiteralDataGenerator literalDataGenerator = new PGPLiteralDataGenerator();
        OutputStream literalOut = literalDataGenerator.open(compressedOut, PGPLiteralData.BINARY, fileName, new Date(),
                new byte[BcPGP.BUFFER_SIZE]);

        // Main loop - read the "in" stream, compress, encrypt and write to the
        // "out" stream
        FileInputStream in = new FileInputStream(fileName);
        byte[] buf = new byte[BcPGP.BUFFER_SIZE];
        int len;
        while ((len = in.read(buf)) > 0) {
            literalOut.write(buf, 0, len);
            signatureGenerator.update(buf, 0, len);
        }

        in.close();
        literalDataGenerator.close();
        // Generate the signature, compress, encrypt and write to the "out"
        // stream
        signatureGenerator.generate().encode(compressedOut);
        compressedDataGenerator.close();
        encryptedDataGenerator.close();
        if (armor) {
            out.close();
        }
    }

    // public static boolean verifyFile(InputStream in, InputStream keyIn,
    // String extractContentFile) throws Exception {
    // in = PGPUtil.getDecoderStream(in);
    //
    // PGPObjectFactory pgpFact = new PGPObjectFactory(in);
    // PGPCompressedData c1 = (PGPCompressedData) pgpFact.nextObject();
    //
    // pgpFact = new PGPObjectFactory(c1.getDataStream());
    //
    // PGPOnePassSignatureList p1 = (PGPOnePassSignatureList)
    // pgpFact.nextObject();
    //
    // PGPOnePassSignature ops = p1.get(0);
    //
    // PGPLiteralData p2 = (PGPLiteralData) pgpFact.nextObject();
    //
    // InputStream dIn = p2.getInputStream();
    //
    // IOUtils.copy(dIn, new FileOutputStream(extractContentFile));
    //
    // int ch;
    // PGPPublicKeyRingCollection pgpRing = new
    // PGPPublicKeyRingCollection(PGPUtil.getDecoderStream(keyIn));
    //
    // PGPPublicKey key = pgpRing.getPublicKey(ops.getKeyID());
    //
    // FileOutputStream out = new FileOutputStream(p2.getFileName());
    //
    // ops.init(new BcPGPContentVerifierBuilderProvider(), key);
    //
    // while ((ch = dIn.read()) >= 0) {
    // ops.update((byte) ch);
    // out.write(ch);
    // }
    //
    // out.close();
    //
    // PGPSignatureList p3 = (PGPSignatureList) pgpFact.nextObject();
    // return ops.verify(p3.get(0));
    // }

    /**
     * From LockBox Lobs PGP Encryption tools.
     * http://www.lockboxlabs.org/content/downloads
     *
     * I didn't think it was worth having to import a 4meg lib for three methods
     * 
     * @param key
     * @return
     */
    public static boolean isForEncryption(PGPPublicKey key) {
        if (key.getAlgorithm() == PublicKeyAlgorithmTags.RSA_SIGN || key.getAlgorithm() == PublicKeyAlgorithmTags.DSA
                || key.getAlgorithm() == PublicKeyAlgorithmTags.EC || key.getAlgorithm() == PublicKeyAlgorithmTags.ECDSA) {
            return false;
        }

        return hasKeyFlags(key, KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE);
    }

    /**
     * From LockBox Lobs PGP Encryption tools.
     * http://www.lockboxlabs.org/content/downloads
     *
     * I didn't think it was worth having to import a 4meg lib for three methods
     * 
     * @param key
     * @return
     */
    private static boolean hasKeyFlags(PGPPublicKey encKey, int keyUsage) {
        if (encKey.isMasterKey()) {
            for (int i = 0; i != BcPGP.MASTER_KEY_CERTIFICATION_TYPES.length; i++) {
                for (Iterator eIt = encKey.getSignaturesOfType(BcPGP.MASTER_KEY_CERTIFICATION_TYPES[i]); eIt.hasNext();) {
                    PGPSignature sig = (PGPSignature) eIt.next();
                    if (!isMatchingUsage(sig, keyUsage)) {
                        return false;
                    }
                }
            }
        } else {
            for (Iterator eIt = encKey.getSignaturesOfType(PGPSignature.SUBKEY_BINDING); eIt.hasNext();) {
                PGPSignature sig = (PGPSignature) eIt.next();
                if (!isMatchingUsage(sig, keyUsage)) {
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * From LockBox Lobs PGP Encryption tools.
     * http://www.lockboxlabs.org/content/downloads
     *
     * I didn't think it was worth having to import a 4meg lib for three methods
     * 
     * @param key
     * @return
     */
    private static boolean isMatchingUsage(PGPSignature sig, int keyUsage) {
        if (sig.hasSubpackets()) {
            PGPSignatureSubpacketVector sv = sig.getHashedSubPackets();
            if (sv.hasSubpacket(BcPGP.KEY_FLAGS)) {
                if ((sv.getKeyFlags() & keyUsage) == 0) {
                    return false;
                }
            }
        }
        return true;
    }
}

FileCopyPGP

public class FileCopyPGP {
    static final String PUBLIC_KEY_PATH = "D:\PGP\public.asc";
    static final String PRIVATE_KEY_PATH = "D:\PGP\secret.asc";
    static final String PASSWORD = "TestPass12345!";

    static final String SOURCE_PATH = "D:\PGP\run\Source.txt";
    static final String ENCRYPTED_PATH = "D:\PGP\run\Encrypted.txt";
    static final String DECRYPTED_PATH = "D:\PGP\run\Decrypted.txt";

    public static void encrypt(InputStream is, OutputStream os) {
        try {
            PGPPublicKey encKey = BcPGP.readPublicKey(new FileInputStream(new File(PUBLIC_KEY_PATH)));
            long start = System.currentTimeMillis();
            System.out.println("Encryption started");
            BcPGP.encryptFile(os, is, encKey, true, true, CompressionAlgorithmTags.UNCOMPRESSED,
                    SymmetricKeyAlgorithmTags.AES_256);
            System.out.println("Encryption ended successfully in " + (System.currentTimeMillis() - start) + "ms");
        } catch (IOException e) {
            System.out.println(e.getMessage());
        } catch (PGPException e) {
            System.out.println(e.getMessage());
        } catch (NoSuchProviderException e) {
            System.out.println(e.getMessage());
        }
    }

    public static void decrypt(InputStream is, OutputStream os) {
        try {
            long start = System.currentTimeMillis();
            System.out.println("Decryption started");
            BcPGP.decryptFile(is, os, new FileInputStream(new File(PRIVATE_KEY_PATH)), PASSWORD.toCharArray());
            System.out.println("Decryption ended successfully in " + (System.currentTimeMillis() - start) + "ms");
        } catch (FileNotFoundException e) {
            System.out.println(e.getMessage());
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

    public static void main(String[] args) throws FileNotFoundException {
        encrypt(new FileInputStream(new File(SOURCE_PATH)), new FileOutputStream(new File(ENCRYPTED_PATH)));
        decrypt(new FileInputStream(new File(ENCRYPTED_PATH)), new FileOutputStream(new File(DECRYPTED_PATH)));
    }
}

在对该主题进行进一步研究时,我发现了这个 SCN post。它激励我做出 3 处更改以使其工作:

  • 我用 post 代码启发了上面给出的代码
  • 我用 bcprov-ext-jdk14-145.jarbcpg-jdk14-145.jar
  • 替换了罐子
  • 我将 jar 文件直接安装到服务器级别的 java/lib/ext 文件夹中(这需要一些 PI 配置)- 而不是将它们作为 IA 导入到存储库中。

post 提到将密钥放入导入的存档中;这意味着如果需要的话很难更换,而且在每个环境(DEV、QA、LIVE ...)中都使用不同的。我上面提供的代码使用 PI 值映射在每个环境中设置指向 public 键的可配置完整文件路径。

import java.io.InputStream;
import java.io.OutputStream;
import java.util.Map;

import com.sap.aii.mapping.api.AbstractTrace;
import com.sap.aii.mapping.api.StreamTransformation;
import com.sap.aii.mapping.api.StreamTransformationConstants;
import com.sap.aii.mapping.api.StreamTransformationException;
import com.sap.aii.mapping.value.api.IFIdentifier;
import com.sap.aii.mapping.value.api.IFRequest;
import com.sap.aii.mapping.value.api.IFResponse;
import com.sap.aii.mapping.value.api.XIVMFactory;
import com.sap.aii.mapping.value.api.XIVMService;

public class PGPEncryptor implements StreamTransformation {
    private Map param;
    private AbstractTrace trace;
    private String receiver = null;
    private static final String SOURCE_AGENCY = "YOUR_SOURCE_AGENCY";
    private static final String SOURCE_SCHEME = "YourKeyPath";
    private static final String TARGET_AGENCY = "YOUR_TARGET_AGENCY";
    private static final String TARGET_SCHEME = "YourKeyPath";

    public void setParameter(Map arg0) {
        param = arg0;
        trace = (AbstractTrace) param.get(StreamTransformationConstants.MAPPING_TRACE);
        receiver = (String) param.get(StreamTransformationConstants.RECEIVER_SERVICE);
    }

    public void execute(InputStream in, OutputStream out) throws StreamTransformationException {
        try {
            IFIdentifier sourceIdentifier = XIVMFactory.newIdentifier(SOURCE_AGENCY, SOURCE_SCHEME);
            IFIdentifier targetIdentifier = XIVMFactory.newIdentifier(TARGET_AGENCY, TARGET_SCHEME);
            IFRequest request = XIVMFactory.newRequest(sourceIdentifier, targetIdentifier, receiver);
            trace.addInfo("Value Mapping lookup value: " + receiver);
            IFResponse response = XIVMService.executeMapping(request);
            String encKey;
            if (response.hasTargetValues()) {
                encKey = response.getSingleTargetValue();
                trace.addInfo("Using key path: " + encKey);
            } else {
                trace.addInfo("Value Mapping lookup parameters");
                trace.addInfo("Source");
                trace.addInfo("Context: " + sourceIdentifier.getContext() + ", Agency: " + SOURCE_AGENCY + ", Scheme: "
                        + SOURCE_SCHEME);
                trace.addInfo("Target");
                trace.addInfo("Context: " + targetIdentifier.getContext() + ", Agency: " + TARGET_AGENCY + ", Scheme: "
                        + TARGET_SCHEME);
                trace.addInfo("Value: " + receiver);
                throw new StreamTransformationException("Public key not found.");
            }

            // Encrypt the message
            long start = System.currentTimeMillis();
            trace.addInfo("Encryption started");
            new PGPCrypto().encrypt(encKey, in, out, trace);
            trace.addInfo("Encryption ended successfully in " + (System.currentTimeMillis() - start) + "ms");
        } catch (Exception e) {
            trace.addInfo(e.getMessage());
        }
    }
}

在下面 class 中要解决的一个重要问题是在创建 PGPPublicKeyRingCollection 之前使用 PGPUtil.getDecoderStream,如下所述:http://www.coderanch.com/t/600592/Security/Bouncy-Castle-API-invalid-header

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Date;
import java.util.Iterator;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openpgp.PGPCompressedDataGenerator;
import org.bouncycastle.openpgp.PGPEncryptedDataGenerator;
import org.bouncycastle.openpgp.PGPLiteralData;
import org.bouncycastle.openpgp.PGPLiteralDataGenerator;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
import org.bouncycastle.openpgp.PGPUtil;

import com.sap.aii.mapping.api.AbstractTrace;

public class PGPCrypto {

    public void encrypt(String publicKeyPath, InputStream in, OutputStream out, AbstractTrace trace) throws Exception {
        try {
            encrypt(publicKeyPath, inputStreamToString(in), out, trace);
        } catch (Exception e) {
            trace.addInfo(e.getMessage());
            throw new Exception(e.toString());
        }
    }

    public void encrypt(String publicKeyPath, String inString, OutputStream out, AbstractTrace trace) throws Exception {
        try {
            Security.addProvider(new BouncyCastleProvider());
            InputStream keyStream = new FileInputStream(publicKeyPath);
            // Get Publik key
            PGPPublicKey key = readPublicKeyFromCol(keyStream);
            out = new DataOutputStream(out);
            ByteArrayOutputStream bOut = new ByteArrayOutputStream();
            PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator(PGPCompressedDataGenerator.ZIP);
            writeStringToLiteralData(comData.open(bOut), inString);
            comData.close();
            // object that encrypts the data
            trace.addInfo("Trace1: Going to encrypt the data");
            PGPEncryptedDataGenerator cPk = new PGPEncryptedDataGenerator(PGPEncryptedDataGenerator.CAST5, new SecureRandom(),
                    "BC");
            cPk.addMethod(key);
            byte[] bytes = bOut.toByteArray();
            out = cPk.open(out, bytes.length);
            out.write(bytes);
            cPk.close();
            out.close();
        } catch (Exception e) {
            trace.addInfo(e.getMessage());
            throw new Exception(e.toString());
        }
    }

    private String inputStreamToString(InputStream in) {
        // read in stream into string.
        StringBuffer buf = new StringBuffer();
        try {
            InputStreamReader isr = null;
            // try UTF-8 conversion
            try {
                isr = new InputStreamReader(in, "UTF-8");
            } catch (UnsupportedEncodingException e) {
                // or atleast in natural encoding
                isr = new InputStreamReader(in);
            }
            int c = 0;
            while ((c = isr.read()) != -1) {
                buf.append((char) c);
            }
            in.close();
            isr.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return buf.toString();
    }

    private void writeStringToLiteralData(OutputStream out, String inString) throws IOException {
        PGPLiteralDataGenerator lData = new PGPLiteralDataGenerator();
        OutputStream pOut = lData.open(out, PGPLiteralData.BINARY, "", inString.length(), new Date());
        pOut.write(inString.getBytes());
        lData.close();
    }

    private PGPPublicKey readPublicKeyFromCol(InputStream in) throws Exception {
        PGPPublicKeyRing pkRing = null;
        PGPPublicKey result = null, key = null;
        try {
            PGPPublicKeyRingCollection pkCol = new PGPPublicKeyRingCollection(PGPUtil.getDecoderStream(in));
            Iterator it = pkCol.getKeyRings();
            while (it.hasNext()) {
                pkRing = (PGPPublicKeyRing) it.next();
                Iterator pkIt = pkRing.getPublicKeys();
                while (pkIt.hasNext()) {
                    key = (PGPPublicKey) pkIt.next();
                    if (key.isEncryptionKey()) {
                        result = key;
                        break;
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception(e.toString());
        }
        return result;
    }
}