Last active
August 27, 2018 12:36
-
-
Save mRB0/64b0499408b88803961aa6eea14d9bb8 to your computer and use it in GitHub Desktop.
Jython scripts to encrypt and decrypt symmetrically using OpenPGP format using BouncyCastle
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env jython | |
import sys | |
sys.path.append('bcprov-jdk15on-160.jar') | |
sys.path.append('bcpg-jdk15on-160.jar') | |
import itertools | |
from org.python.core.io import StreamIO | |
import jarray | |
from java.nio.charset import Charset | |
from java.util import Date | |
from org.bouncycastle.openpgp import * | |
from org.bouncycastle.openpgp.bc import * | |
from org.bouncycastle.openpgp.operator import * | |
from org.bouncycastle.openpgp.operator.bc import * | |
from org.bouncycastle.bcpg import * | |
def objectFactoryIterator(objectFactory): | |
try: | |
yield objectFactory.nextObject() | |
except e: | |
print("(error getting object: {})", e) | |
def dprint(depth, what): | |
print(" " * depth + what) | |
compressionTypes = { | |
CompressionAlgorithmTags.BZIP2: "bzip2", | |
CompressionAlgorithmTags.UNCOMPRESSED: "uncompressed", | |
CompressionAlgorithmTags.ZIP: "zip", | |
CompressionAlgorithmTags.ZLIB: "zlib" | |
} | |
formatTags = { | |
ord(PGPLiteralData.BINARY): "binary", | |
ord(PGPLiteralData.TEXT): "text", | |
ord(PGPLiteralData.UTF8): "utf-8 text" | |
} | |
class Decryptor(object): | |
def __init__(self, filename, passphrase): | |
self.decryptedCount = 0 | |
self.passphrase = passphrase | |
self.filename = filename | |
with open(self.filename, 'rb') as inputFile: | |
objectFactory = BcPGPObjectFactory(inputFile) | |
self.handleObjectFactory(0, objectFactory) | |
def handleObjectFactory(self, depth, objectFactory): | |
for i, pgpObj in enumerate(objectFactoryIterator(objectFactory)): | |
dprint(depth, "Object {} is a {!r}".format(i, pgpObj)) | |
self.handlePGPObject(depth + 1, pgpObj) | |
def handlePBEEncryptedData(self, depth, encryptedData): | |
dprint(depth, "Decrypt") | |
clearDataStream = encryptedData.getDataStream(BcPBEDataDecryptorFactory(self.passphrase, BcPGPDigestCalculatorProvider())) | |
try: | |
self.handleObjectFactory(depth + 1, BcPGPObjectFactory(clearDataStream)) | |
finally: | |
clearDataStream.close() | |
if encryptedData.isIntegrityProtected(): | |
dprint(depth, "Encrypted data was integrity protected; valid = {}".format(encryptedData.verify())) | |
def handleCompressedData(self, depth, compressedData): | |
algorithm = compressedData.getAlgorithm() | |
dprint(depth, "Uncompress compressed data (algorithm={})".format(compressionTypes.get(algorithm, algorithm))) | |
uncompressedDataStream = compressedData.getDataStream() | |
try: | |
self.handleObjectFactory(depth + 1, BcPGPObjectFactory(uncompressedDataStream)) | |
finally: | |
uncompressedDataStream.close() | |
def handleLiteralData(self, depth, literalData): | |
formatTag = literalData.getFormat() | |
dprint(depth, "Literal data, format={}, modified={}".format( | |
formatTags.get(formatTag, formatTag), | |
literalData.getModificationTime()) | |
) | |
inputStream = literalData.getInputStream() | |
try: | |
filename = "/tmp/decrypted{}".format("" if self.decryptedCount == 0 else "-{}".format(self.decryptedCount + 1)) | |
with open(filename, 'wb') as outputFile: | |
buf = jarray.zeros(2048, 'b') | |
totalBytesRead = 0 | |
for bytesRead in itertools.takewhile(lambda br: br != -1, (inputStream.read(buf) for _ in itertools.repeat(0))): | |
outputFile.write(buf[0:bytesRead]) | |
totalBytesRead += bytesRead | |
self.decryptedCount += 1 | |
dprint(depth, "Saved {} bytes to {}".format(totalBytesRead, filename)) | |
finally: | |
inputStream.close() | |
def handlePGPObject(self, depth, pgpObj): | |
dprint(depth, "Handle {!r}".format(pgpObj)) | |
if isinstance(pgpObj, PGPEncryptedDataList): | |
for encryptedData in pgpObj: | |
self.handlePGPObject(depth + 1, encryptedData) | |
elif isinstance(pgpObj, PGPPBEEncryptedData): | |
self.handlePBEEncryptedData(depth + 1, pgpObj) | |
elif isinstance(pgpObj, PGPCompressedData): | |
self.handleCompressedData(depth + 1, pgpObj) | |
elif isinstance(pgpObj, PGPLiteralData): | |
self.handleLiteralData(depth + 1, pgpObj) | |
else: | |
dprint(depth, "Skipping unsupported PGP object {!r}".format(pgpObj)) | |
def decrypt(filename, passphrase): | |
Decryptor(filename, passphrase) | |
if __name__ == '__main__': | |
if len(sys.argv) < 3: | |
print("usage: {} encryptedFile passphrase".format(sys.argv[0])) | |
else: | |
decrypt(sys.argv[1], sys.argv[2]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env jython | |
from __future__ import division | |
import sys | |
sys.path.append('bcprov-jdk15on-160.jar') | |
sys.path.append('bcpg-jdk15on-160.jar') | |
import os | |
import itertools | |
from java.nio.charset import Charset | |
from java.util import Date | |
from org.bouncycastle.openpgp import PGPEncryptedDataGenerator, PGPCompressedDataGenerator, PGPLiteralDataGenerator | |
from org.bouncycastle.bcpg import SymmetricKeyAlgorithmTags | |
from org.bouncycastle.openpgp.operator.bc import BcPBEKeyEncryptionMethodGenerator, BcPGPDataEncryptorBuilder | |
bufferSize = 65536 | |
def encrypt(filename, outputFile, passphrase): | |
builder = BcPGPDataEncryptorBuilder(SymmetricKeyAlgorithmTags.AES_256) | |
builder.setWithIntegrityPacket(True) | |
generator = PGPEncryptedDataGenerator(builder) | |
encryptionMethod = BcPBEKeyEncryptionMethodGenerator(passphrase) | |
generator.addMethod(encryptionMethod) | |
def writeFile(outputStream): | |
with open(filename, 'rb') as inFile: | |
totalBytesRead = 0 | |
fileSize = os.path.getsize(filename) | |
for data in itertools.takewhile(lambda b: b, (inFile.read(bufferSize) for _ in itertools.repeat(0))): | |
outputStream.write(data) | |
totalBytesRead += len(data) | |
print("{}/{} ({:.2f}%)".format(totalBytesRead, fileSize, totalBytesRead / fileSize * 100)) | |
import jarray | |
buf = jarray.zeros(bufferSize, 'b') | |
print("Writing to {}".format(outputFile)) | |
with open(outputFile, 'wb') as outputFile: | |
generatorStream = generator.open(outputFile, buf) | |
try: | |
compressorStream = PGPCompressedDataGenerator(PGPCompressedDataGenerator.ZIP).open(generatorStream) | |
try: | |
buf2 = jarray.zeros(bufferSize, 'b') | |
literalStream = PGPLiteralDataGenerator().open(compressorStream, PGPLiteralDataGenerator.BINARY, os.path.basename(filename), Date(), buf2) | |
try: | |
writeFile(literalStream) | |
finally: | |
literalStream.close() | |
finally: | |
compressorStream.close() | |
finally: | |
generatorStream.close() | |
if __name__ == '__main__': | |
if len(sys.argv) < 4: | |
print("usage: {} plaintextFile outputFile passphrase".format(sys.argv[0])) | |
else: | |
encrypt(sys.argv[1], sys.argv[2], sys.argv[3]) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment