Skip to content

Commit

Permalink
Add PGP encrypt/decrypt functions with files
Browse files Browse the repository at this point in the history
  • Loading branch information
TharmiganK committed Oct 2, 2024
1 parent 85c3173 commit 3ac65fd
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 7 deletions.
31 changes: 31 additions & 0 deletions ballerina/encrypt_decrypt.bal
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,21 @@ public isolated function encryptPgp(byte[] plainText, string publicKeyPath, *Opt
'class: "io.ballerina.stdlib.crypto.nativeimpl.Encrypt"
} external;

# Writes the PGP-encrypted value of the given data to a file specified by the output file path.
# ```ballerina
# check crypto:encryptPgpAsFile("input.txt", "public_key.asc", "output.txt");
# ```
#
# + inputFilePath - Path to the input file
# + publicKeyPath - Path to the public key
# + outputFilePath - Path to the output file
# + options - PGP encryption options
# + return - A `crypto:Error` will be returned if the process fails
public isolated function encryptPgpAsFile(string inputFilePath, string publicKeyPath, string outputFilePath,
*Options options) returns Error? = @java:Method {
'class: "io.ballerina.stdlib.crypto.nativeimpl.Encrypt"
} external;

Check warning on line 276 in ballerina/encrypt_decrypt.bal

View check run for this annotation

Codecov / codecov/patch

ballerina/encrypt_decrypt.bal#L276

Added line #L276 was not covered by tests

# Returns the PGP-decrypted value of the given PGP-encrypted data.
# ```ballerina
# byte[] message = "Hello Ballerina!".toBytes();
Expand All @@ -278,3 +293,19 @@ public isolated function decryptPgp(byte[] cipherText, string privateKeyPath, by
name: "decryptPgp",
'class: "io.ballerina.stdlib.crypto.nativeimpl.Decrypt"
} external;

# Writes the PGP-decrypted value of the given data to a file specified by the output file path.
# ```ballerina
# byte[] passphrase = check io:fileReadBytes("pass_phrase.txt");
# check crypto:decryptPgpAsFile("input.txt", "private_key.asc", passphrase, "output.txt");
# ```
#
# + inputFilePath - Path to the input file
# + privateKeyPath - Path to the private key
# + passphrase - passphrase of the private key
# + outputFilePath - Path to the output file
# + return - A `crypto:Error` will be returned if the process fails
public isolated function decryptPgpAsFile(string inputFilePath, string privateKeyPath, byte[] passphrase,
string outputFilePath) returns Error? = @java:Method {
'class: "io.ballerina.stdlib.crypto.nativeimpl.Decrypt"
} external;

Check warning on line 311 in ballerina/encrypt_decrypt.bal

View check run for this annotation

Codecov / codecov/patch

ballerina/encrypt_decrypt.bal#L311

Added line #L311 was not covered by tests
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.Security;
import java.util.Iterator;
import java.util.Objects;
Expand Down Expand Up @@ -123,6 +125,12 @@ public Object decrypt(byte[] encryptedBytes) throws PGPException, IOException {
}
}

public void decrypt(InputStream encryptedIn, String outputPath) throws PGPException, IOException {
try (OutputStream outputStream = Files.newOutputStream(Path.of(outputPath))) {
decryptStream(encryptedIn, outputStream);

Check warning on line 130 in native/src/main/java/io/ballerina/stdlib/crypto/PgpDecryptionGenerator.java

View check run for this annotation

Codecov / codecov/patch

native/src/main/java/io/ballerina/stdlib/crypto/PgpDecryptionGenerator.java#L129-L130

Added lines #L129 - L130 were not covered by tests
}
}

Check warning on line 132 in native/src/main/java/io/ballerina/stdlib/crypto/PgpDecryptionGenerator.java

View check run for this annotation

Codecov / codecov/patch

native/src/main/java/io/ballerina/stdlib/crypto/PgpDecryptionGenerator.java#L132

Added line #L132 was not covered by tests

private static void decrypt(OutputStream clearOut, Optional<PGPPrivateKey> pgpPrivateKey,
PGPPublicKeyEncryptedData publicKeyEncryptedData) throws IOException, PGPException {
if (pgpPrivateKey.isPresent()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.SecureRandom;
import java.security.Security;
import java.time.LocalDateTime;
Expand Down Expand Up @@ -76,7 +78,7 @@ public PgpEncryptionGenerator(int compressionAlgorithm, int symmetricKeyAlgorith
this.withIntegrityCheck = withIntegrityCheck;
}

private void encryptStream(OutputStream encryptOut, InputStream clearIn, long length, InputStream publicKeyIn)
private void encryptStream(OutputStream encryptOut, InputStream clearIn, InputStream publicKeyIn)
throws IOException, PGPException {
PGPCompressedDataGenerator compressedDataGenerator =
new PGPCompressedDataGenerator(compressionAlgorithm);
Expand All @@ -95,7 +97,7 @@ private void encryptStream(OutputStream encryptOut, InputStream clearIn, long le
}

try (OutputStream cipherOutStream = pgpEncryptedDataGenerator.open(encryptOut, new byte[BUFFER_SIZE])) {
copyAsLiteralData(compressedDataGenerator.open(cipherOutStream), clearIn, length);
copyAsLiteralData(compressedDataGenerator.open(cipherOutStream), clearIn);
compressedDataGenerator.close();
}
encryptOut.close();
Expand All @@ -105,11 +107,18 @@ private void encryptStream(OutputStream encryptOut, InputStream clearIn, long le
public Object encrypt(byte[] clearData, InputStream publicKeyIn) throws PGPException, IOException {
try (ByteArrayInputStream inputStream = new ByteArrayInputStream(clearData);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
encryptStream(outputStream, inputStream, clearData.length, publicKeyIn);
encryptStream(outputStream, inputStream, publicKeyIn);
return ValueCreator.createArrayValue(outputStream.toByteArray());
}
}

public void encrypt(InputStream inputStream, InputStream publicKeyIn, String outputPath)
throws PGPException, IOException {
try (OutputStream outputStream = Files.newOutputStream(Path.of(outputPath))) {
encryptStream(outputStream, inputStream, publicKeyIn);

Check warning on line 118 in native/src/main/java/io/ballerina/stdlib/crypto/PgpEncryptionGenerator.java

View check run for this annotation

Codecov / codecov/patch

native/src/main/java/io/ballerina/stdlib/crypto/PgpEncryptionGenerator.java#L117-L118

Added lines #L117 - L118 were not covered by tests
}
}

Check warning on line 120 in native/src/main/java/io/ballerina/stdlib/crypto/PgpEncryptionGenerator.java

View check run for this annotation

Codecov / codecov/patch

native/src/main/java/io/ballerina/stdlib/crypto/PgpEncryptionGenerator.java#L120

Added line #L120 was not covered by tests

private static PGPPublicKey getPublicKey(InputStream keyInputStream) throws IOException, PGPException {
PGPPublicKeyRingCollection pgpPublicKeyRings = new PGPPublicKeyRingCollection(
PGPUtil.getDecoderStream(keyInputStream), new JcaKeyFingerprintCalculator());
Expand All @@ -124,7 +133,7 @@ private static PGPPublicKey getPublicKey(InputStream keyInputStream) throws IOEx
throw new PGPException("Invalid public key");
}

private static void copyAsLiteralData(OutputStream outputStream, InputStream in, long length)
private static void copyAsLiteralData(OutputStream outputStream, InputStream in)
throws IOException {
PGPLiteralDataGenerator lData = new PGPLiteralDataGenerator();
byte[] buff = new byte[PgpEncryptionGenerator.BUFFER_SIZE];
Expand All @@ -133,10 +142,8 @@ private static void copyAsLiteralData(OutputStream outputStream, InputStream in,
InputStream inputStream = in) {

int len;
long totalBytesWritten = 0L;
while (totalBytesWritten <= length && (len = inputStream.read(buff)) > 0) {
while ((len = inputStream.read(buff)) > 0) {
pOut.write(buff, 0, len);
totalBytesWritten += len;
}
} finally {
Arrays.fill(buff, (byte) 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,4 +100,24 @@ public static Object decryptPgp(BArray cipherTextValue, BString privateKeyPath,
return CryptoUtils.createError("Error occurred while PGP decrypt: " + e.getMessage());
}
}

public static Object decryptPgpAsFile(BString inputFilePath, BString privateKeyPath, BArray passphrase,
BString outputFilePath) {
byte[] passphraseInBytes = passphrase.getBytes();

Check warning on line 106 in native/src/main/java/io/ballerina/stdlib/crypto/nativeimpl/Decrypt.java

View check run for this annotation

Codecov / codecov/patch

native/src/main/java/io/ballerina/stdlib/crypto/nativeimpl/Decrypt.java#L106

Added line #L106 was not covered by tests
byte[] privateKey;
try {
privateKey = Files.readAllBytes(Path.of(privateKeyPath.toString()));
} catch (IOException e) {
return CryptoUtils.createError("Error occurred while reading public key: " + e.getMessage());
}

Check warning on line 112 in native/src/main/java/io/ballerina/stdlib/crypto/nativeimpl/Decrypt.java

View check run for this annotation

Codecov / codecov/patch

native/src/main/java/io/ballerina/stdlib/crypto/nativeimpl/Decrypt.java#L109-L112

Added lines #L109 - L112 were not covered by tests

try (InputStream keyStream = new ByteArrayInputStream(privateKey);
InputStream cipherTextStream = Files.newInputStream(Path.of(inputFilePath.toString()))) {
PgpDecryptionGenerator pgpDecryptionGenerator = new PgpDecryptionGenerator(keyStream, passphraseInBytes);
pgpDecryptionGenerator.decrypt(cipherTextStream, outputFilePath.getValue());
return null;
} catch (IOException | PGPException e) {
return CryptoUtils.createError("Error occurred while PGP decrypt: " + e.getMessage());

Check warning on line 120 in native/src/main/java/io/ballerina/stdlib/crypto/nativeimpl/Decrypt.java

View check run for this annotation

Codecov / codecov/patch

native/src/main/java/io/ballerina/stdlib/crypto/nativeimpl/Decrypt.java#L114-L120

Added lines #L114 - L120 were not covered by tests
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -116,4 +116,29 @@ public static Object encryptPgp(BArray plainTextValue, BString publicKeyPath, BM
return CryptoUtils.createError("Error occurred while PGP encrypt: " + e.getMessage());
}
}

public static Object encryptPgpAsFile(BString inputFilePath, BString publicKeyPath, BString outputFilePath,
BMap options) {
byte[] publicKey;
try {
publicKey = Files.readAllBytes(Path.of(publicKeyPath.toString()));
} catch (IOException e) {
return CryptoUtils.createError("Error occurred while reading public key: " + e.getMessage());
}

Check warning on line 127 in native/src/main/java/io/ballerina/stdlib/crypto/nativeimpl/Encrypt.java

View check run for this annotation

Codecov / codecov/patch

native/src/main/java/io/ballerina/stdlib/crypto/nativeimpl/Encrypt.java#L124-L127

Added lines #L124 - L127 were not covered by tests

try (InputStream publicKeyStream = new ByteArrayInputStream(publicKey);
InputStream inputStream = Files.newInputStream(Path.of(inputFilePath.toString()))

Check warning on line 130 in native/src/main/java/io/ballerina/stdlib/crypto/nativeimpl/Encrypt.java

View check run for this annotation

Codecov / codecov/patch

native/src/main/java/io/ballerina/stdlib/crypto/nativeimpl/Encrypt.java#L129-L130

Added lines #L129 - L130 were not covered by tests
) {
PgpEncryptionGenerator pgpEncryptionGenerator = new PgpEncryptionGenerator(
Integer.parseInt(options.get(COMPRESSION_ALGORITHM).toString()),
Integer.parseInt(options.get(SYMMETRIC_KEY_ALGORITHM).toString()),
Boolean.parseBoolean(options.get(ARMOR).toString()),
Boolean.parseBoolean(options.get(WITH_INTEGRITY_CHECK).toString())

Check warning on line 136 in native/src/main/java/io/ballerina/stdlib/crypto/nativeimpl/Encrypt.java

View check run for this annotation

Codecov / codecov/patch

native/src/main/java/io/ballerina/stdlib/crypto/nativeimpl/Encrypt.java#L132-L136

Added lines #L132 - L136 were not covered by tests
);
pgpEncryptionGenerator.encrypt(inputStream, publicKeyStream, outputFilePath.getValue());
return null;
} catch (IOException | PGPException e) {
return CryptoUtils.createError("Error occurred while PGP encrypt: " + e.getMessage());

Check warning on line 141 in native/src/main/java/io/ballerina/stdlib/crypto/nativeimpl/Encrypt.java

View check run for this annotation

Codecov / codecov/patch

native/src/main/java/io/ballerina/stdlib/crypto/nativeimpl/Encrypt.java#L138-L141

Added lines #L138 - L141 were not covered by tests
}
}
}

0 comments on commit 3ac65fd

Please sign in to comment.