Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
M
MyAzureFunctionsDemo
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Abdullah Danish
MyAzureFunctionsDemo
Commits
a703b7c8
Commit
a703b7c8
authored
Sep 19, 2022
by
Abdullah Danish
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'GAFP-4' into 'master'
[GAFP-4] : PGP Encryption/Decryption See merge request
!3
parents
ca8d081a
0bee5cfc
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
623 additions
and
6 deletions
+623
-6
BlobTriggerFunction.java
.../java/com/nisum/demo/blobStorage/BlobTriggerFunction.java
+58
-5
DecryptService.java
src/main/java/com/nisum/demo/blobStorage/DecryptService.java
+27
-0
PGPUtils.java
src/main/java/com/nisum/demo/blobStorage/PGPUtils.java
+324
-0
application.properties
src/main/resources/application.properties
+5
-1
gappoc.asc
src/main/resources/keys/gappoc.asc
+158
-0
gappocPublic.asc
src/main/resources/keys/gappocPublic.asc
+51
-0
No files found.
src/main/java/com/nisum/demo/blobStorage/BlobTriggerFunction.java
View file @
a703b7c8
...
@@ -2,7 +2,19 @@ package com.nisum.demo.blobStorage;
...
@@ -2,7 +2,19 @@ package com.nisum.demo.blobStorage;
import
com.microsoft.azure.functions.annotation.*
;
import
com.microsoft.azure.functions.annotation.*
;
import
com.microsoft.azure.functions.*
;
import
com.microsoft.azure.functions.*
;
import
java.io.IOException
;
import
org.bouncycastle.openpgp.PGPException
;
import
org.bouncycastle.openpgp.PGPPublicKey
;
import
org.bouncycastle.openpgp.PGPSecretKey
;
import
java.io.*
;
import
java.nio.file.Files
;
import
java.nio.file.Paths
;
import
java.security.NoSuchAlgorithmException
;
import
java.security.NoSuchProviderException
;
import
java.security.SignatureException
;
import
java.util.PropertyResourceBundle
;
import
java.util.ResourceBundle
;
import
java.util.regex.Pattern
;
/**
/**
* Azure Functions with Azure Blob trigger.
* Azure Functions with Azure Blob trigger.
...
@@ -13,12 +25,53 @@ public class BlobTriggerFunction {
...
@@ -13,12 +25,53 @@ public class BlobTriggerFunction {
*/
*/
@FunctionName
(
"BlobTriggerFunc"
)
@FunctionName
(
"BlobTriggerFunc"
)
public
void
run
(
public
void
run
(
@BlobTrigger
(
name
=
"inbound"
,
path
=
"test/{name}"
,
dataType
=
"binary"
,
@BlobTrigger
(
name
=
"file"
,
path
=
"test/{name}"
,
dataType
=
"binary"
,
connection
=
"AzureWebJobsStorage"
)
byte
[]
content
,
connection
=
"AzureWebJobsStorage"
)
byte
[]
content
,
@BindingName
(
"name"
)
String
name
,
@BindingName
(
"name"
)
String
name
,
final
ExecutionContext
context
final
ExecutionContext
context
)
throws
IOException
{
)
throws
IOException
{
context
.
getLogger
().
info
(
"Java Blob trigger function processed a blob. Name: "
+
ResourceBundle
resourceBundle
=
new
PropertyResourceBundle
(
new
FileInputStream
(
"/Users/eali/Projects/azure/myazurefunctionsdemo/src/main/resources/application.properties"
));
name
+
"\n Size: "
+
content
.
length
+
" Bytes"
);
if
(
Pattern
.
matches
(
"[a-z|A-Z]*.csv"
,
name
))
{
String
directoryPath
=
resourceBundle
.
getString
(
"files.directory.path"
)
+
name
;
if
(!
Files
.
exists
(
Paths
.
get
(
directoryPath
)))
{
Files
.
createFile
(
Paths
.
get
(
directoryPath
));
}
try
(
FileOutputStream
fileOutputStream
=
new
FileOutputStream
(
directoryPath
,
true
))
{
fileOutputStream
.
write
(
content
);
}
InputStream
inputStreamSecretKey
=
new
FileInputStream
(
resourceBundle
.
getString
(
"gpg.keychain.secret.key"
));
InputStream
inputStreamPublicKey
=
new
FileInputStream
(
resourceBundle
.
getString
(
"gpg.keychain.public.key"
));
char
[]
pass
=
{
'n'
,
'i'
,
's'
,
'u'
,
'm'
,
'1'
,
'2'
,
'3'
,
'4'
};
// Writes data to the output stream
OutputStream
outbound
=
new
FileOutputStream
(
resourceBundle
.
getString
(
"encrypted.files.directory.path"
)
+
name
.
replaceFirst
(
".csv"
,
".asc"
));
String
inbound
=
resourceBundle
.
getString
(
"files.directory.path"
)
+
name
;
try
{
// use it when using only public key
// PGPPublicKey key = PGPUtils.readPublicKey(inputStream);
// use it to get secret key when using public + private key
// PGPSecretKey pgpSecretKey = PGPUtils.readSecretKey(inputStream);
// for encryption
PGPUtils
.
encryptAndSignFile
(
outbound
,
inbound
,
inputStreamPublicKey
,
inputStreamSecretKey
,
true
,
true
,
pass
);
context
.
getLogger
().
info
(
"---File Encrypted---"
);
// for decryption
// InputStream fileToBeDecrypt = new FileInputStream(resourceBundle.getString("encrypted.files.directory.path") + name.replaceFirst(".csv", ".asc"));
// OutputStream inboundN = new FileOutputStream(resourceBundle.getString("decrypted.files.directory.path"));
// PGPUtils.decryptFile(fileToBeDecrypt, inboundN, inputStreamSecretKey, pass, inputStreamPublicKey);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
}
// Closes the output stream
}
context
.
getLogger
().
info
(
"Java Blob trigger function processed a blob. Name: "
+
name
+
"\n Size: "
+
content
.
length
+
" Bytes"
);
}
}
}
}
src/main/java/com/nisum/demo/blobStorage/DecryptService.java
0 → 100644
View file @
a703b7c8
package
com
.
nisum
.
demo
.
blobStorage
;
import
java.io.IOException
;
import
java.security.NoSuchProviderException
;
import
java.security.SignatureException
;
import
org.bouncycastle.openpgp.PGPException
;
public
abstract
class
DecryptService
{
/**
* Decrypt the input file and move it to output folder.
*
* @param inputPath encrypted file path
* @param outputPath destination file path
* @param secretKeyPath secret key file path
* @param partnerPublicKeyPath partner public key file path
* @param passPhrase pass phrase use to generate secret key
* @throws NoSuchProviderException thrown when security provider not found
* @throws IOException throws when unable accessing file path.
* @throws PGPException thrown when error performing PGP decryption
* @throws SignatureException when error performing verification of signature
*/
abstract
void
decrypt
(
String
inputPath
,
String
outputPath
,
String
secretKeyPath
,
String
partnerPublicKeyPath
,
String
passPhrase
)
throws
NoSuchProviderException
,
IOException
,
PGPException
,
SignatureException
;
}
src/main/java/com/nisum/demo/blobStorage/PGPUtils.java
0 → 100644
View file @
a703b7c8
package
com
.
nisum
.
demo
.
blobStorage
;
import
java.io.ByteArrayOutputStream
;
import
java.io.File
;
import
java.io.FileInputStream
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.OutputStream
;
import
java.security.NoSuchAlgorithmException
;
import
java.security.NoSuchProviderException
;
import
java.security.SecureRandom
;
import
java.security.Security
;
import
java.security.SignatureException
;
import
java.util.Date
;
import
java.util.Iterator
;
import
org.bouncycastle.bcpg.ArmoredOutputStream
;
import
org.bouncycastle.jce.provider.BouncyCastleProvider
;
import
org.bouncycastle.openpgp.PGPCompressedData
;
import
org.bouncycastle.openpgp.PGPCompressedDataGenerator
;
import
org.bouncycastle.openpgp.PGPEncryptedData
;
import
org.bouncycastle.openpgp.PGPEncryptedDataGenerator
;
import
org.bouncycastle.openpgp.PGPEncryptedDataList
;
import
org.bouncycastle.openpgp.PGPException
;
import
org.bouncycastle.openpgp.PGPLiteralData
;
import
org.bouncycastle.openpgp.PGPLiteralDataGenerator
;
import
org.bouncycastle.openpgp.PGPObjectFactory
;
import
org.bouncycastle.openpgp.PGPOnePassSignature
;
import
org.bouncycastle.openpgp.PGPOnePassSignatureList
;
import
org.bouncycastle.openpgp.PGPPrivateKey
;
import
org.bouncycastle.openpgp.PGPPublicKey
;
import
org.bouncycastle.openpgp.PGPPublicKeyEncryptedData
;
import
org.bouncycastle.openpgp.PGPPublicKeyRing
;
import
org.bouncycastle.openpgp.PGPPublicKeyRingCollection
;
import
org.bouncycastle.openpgp.PGPSecretKey
;
import
org.bouncycastle.openpgp.PGPSecretKeyRing
;
import
org.bouncycastle.openpgp.PGPSecretKeyRingCollection
;
import
org.bouncycastle.openpgp.PGPSignature
;
import
org.bouncycastle.openpgp.PGPSignatureGenerator
;
import
org.bouncycastle.openpgp.PGPSignatureList
;
import
org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator
;
import
org.bouncycastle.openpgp.PGPUtil
;
import
org.bouncycastle.util.io.Streams
;
public
class
PGPUtils
{
/**
* private constructor for utility class.
*/
private
PGPUtils
()
{
}
/**
* Load a secret key ring collection from keyIn and find the secret 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 private key
* @throws IOException exception
* @throws PGPException exception
* @throws NoSuchProviderException exception
*/
static
PGPPrivateKey
findSecretKey
(
InputStream
keyIn
,
long
keyID
,
char
[]
pass
)
throws
IOException
,
PGPException
,
NoSuchProviderException
{
PGPSecretKeyRingCollection
pgpSec
=
new
PGPSecretKeyRingCollection
(
org
.
bouncycastle
.
openpgp
.
PGPUtil
.
getDecoderStream
(
keyIn
));
PGPSecretKey
pgpSecKey
=
pgpSec
.
getSecretKey
(
keyID
);
if
(
pgpSecKey
==
null
)
{
return
null
;
}
return
pgpSecKey
.
extractPrivateKey
(
pass
,
"BC"
);
}
/**
* Iterate through key ring collection to find secret key.
*
* @param secretKeyInputStream path to secret key
* @return PGP secret key
* @throws IOException exception when performing file operation
* @throws PGPException exception when finding key in ring collection
*/
static
PGPSecretKey
readSecretKey
(
InputStream
secretKeyInputStream
)
throws
IOException
,
PGPException
{
PGPSecretKeyRingCollection
keyRingCollection
=
new
PGPSecretKeyRingCollection
(
PGPUtil
.
getDecoderStream
(
secretKeyInputStream
));
Iterator
keyRingIterator
=
keyRingCollection
.
getKeyRings
();
while
(
keyRingIterator
.
hasNext
())
{
PGPSecretKeyRing
keyRing
=
(
PGPSecretKeyRing
)
keyRingIterator
.
next
();
Iterator
keyIterator
=
keyRing
.
getSecretKeys
();
while
(
keyIterator
.
hasNext
())
{
PGPSecretKey
secretKey
=
(
PGPSecretKey
)
keyIterator
.
next
();
if
(
secretKey
.
isSigningKey
())
{
return
secretKey
;
}
}
}
throw
new
IllegalArgumentException
(
"Unable to find signing key in key ring."
);
}
/**
* Iterate through key ring collection to find public key.
*
* @param publicKeyInputStream path to public key
* @return PGP public key
* @throws IOException exception when performing file operation
* @throws PGPException exception when finding key in ring collection
*/
static
PGPPublicKey
readPublicKey
(
InputStream
publicKeyInputStream
)
throws
IOException
,
PGPException
{
publicKeyInputStream
=
PGPUtil
.
getDecoderStream
(
publicKeyInputStream
);
PGPPublicKeyRingCollection
keyRingCollection
=
new
PGPPublicKeyRingCollection
(
publicKeyInputStream
);
PGPPublicKey
partnerPublicKey
=
null
;
// iterate through the key rings.
Iterator
<
PGPPublicKeyRing
>
keyRings
=
keyRingCollection
.
getKeyRings
();
while
(
partnerPublicKey
==
null
&&
keyRings
.
hasNext
())
{
PGPPublicKeyRing
keyRing
=
keyRings
.
next
();
Iterator
<
PGPPublicKey
>
publicKeys
=
keyRing
.
getPublicKeys
();
while
(
partnerPublicKey
==
null
&&
publicKeys
.
hasNext
())
{
PGPPublicKey
publicKey
=
publicKeys
.
next
();
if
(
publicKey
.
isEncryptionKey
())
{
partnerPublicKey
=
publicKey
;
}
}
}
if
(
partnerPublicKey
==
null
)
{
throw
new
IllegalArgumentException
(
"Unable to find encryption key in key ring."
);
}
return
partnerPublicKey
;
}
/**
* decrypt and verify the passed in message stream.
*
* @param in input stream for encrypted file
* @param out output stream for decrypted file
* @param keyIn input stream for secret key file
* @param passwd passphrase
* @param publicKeyIn public key of partner
* @throws IOException exception
* @throws PGPException exception
* @throws NoSuchProviderException exception
* @throws SignatureException exception
*/
public
static
void
decryptFile
(
InputStream
in
,
OutputStream
out
,
InputStream
keyIn
,
char
[]
passwd
,
InputStream
publicKeyIn
)
throws
IOException
,
NoSuchProviderException
,
SignatureException
,
PGPException
{
Security
.
addProvider
(
new
BouncyCastleProvider
());
in
=
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
<
PGPPublicKeyEncryptedData
>
it
=
enc
.
getEncryptedDataObjects
();
PGPPrivateKey
sKey
=
null
;
PGPPublicKeyEncryptedData
pbe
=
null
;
while
(
sKey
==
null
&&
it
.
hasNext
())
{
pbe
=
it
.
next
();
sKey
=
findSecretKey
(
keyIn
,
pbe
.
getKeyID
(),
passwd
);
}
if
(
sKey
==
null
)
{
throw
new
IllegalArgumentException
(
"secret key for message not found."
);
}
InputStream
clear
=
pbe
.
getDataStream
(
sKey
,
"BC"
);
PGPObjectFactory
plainFact
=
new
PGPObjectFactory
(
clear
);
PGPOnePassSignatureList
onePassSignatureList
=
null
;
PGPSignatureList
signatureList
=
null
;
PGPCompressedData
compressedData
;
Object
message
=
plainFact
.
nextObject
();
ByteArrayOutputStream
actualOutput
=
new
ByteArrayOutputStream
();
while
(
message
!=
null
)
{
if
(
message
instanceof
PGPCompressedData
)
{
compressedData
=
(
PGPCompressedData
)
message
;
plainFact
=
new
PGPObjectFactory
(
compressedData
.
getDataStream
());
message
=
plainFact
.
nextObject
();
}
if
(
message
instanceof
PGPLiteralData
)
{
// have to read it and keep it somewhere.
Streams
.
pipeAll
(((
PGPLiteralData
)
message
).
getInputStream
(),
actualOutput
);
}
else
if
(
message
instanceof
PGPOnePassSignatureList
)
{
onePassSignatureList
=
(
PGPOnePassSignatureList
)
message
;
}
else
if
(
message
instanceof
PGPSignatureList
)
{
signatureList
=
(
PGPSignatureList
)
message
;
}
else
{
throw
new
PGPException
(
"message unknown message type."
);
}
message
=
plainFact
.
nextObject
();
}
actualOutput
.
close
();
PGPPublicKey
publicKey
=
null
;
byte
[]
output
=
actualOutput
.
toByteArray
();
if
(
onePassSignatureList
==
null
||
signatureList
==
null
)
{
throw
new
PGPException
(
"Poor PGP. Signatures not found."
);
}
else
{
for
(
int
i
=
0
;
i
<
onePassSignatureList
.
size
();
i
++)
{
PGPOnePassSignature
ops
=
onePassSignatureList
.
get
(
0
);
PGPPublicKeyRingCollection
pgpRing
=
new
PGPPublicKeyRingCollection
(
PGPUtil
.
getDecoderStream
(
publicKeyIn
));
publicKey
=
pgpRing
.
getPublicKey
(
ops
.
getKeyID
());
if
(
publicKey
!=
null
)
{
ops
.
initVerify
(
publicKey
,
"BC"
);
ops
.
update
(
output
);
PGPSignature
signature
=
signatureList
.
get
(
i
);
if
(!
ops
.
verify
(
signature
))
{
throw
new
SignatureException
(
"Signature Verification failed"
);
}
}
}
}
if
(
pbe
.
isIntegrityProtected
()
&&
!
pbe
.
verify
())
{
throw
new
PGPException
(
"Data is integrity protected but integrity is lost."
);
}
else
if
(
publicKey
==
null
)
{
throw
new
SignatureException
(
"Signature not found"
);
}
else
{
out
.
write
(
output
);
out
.
flush
();
out
.
close
();
}
}
/**
* Encrypt file using public key provided and sign it with secret key
* provided.
*
* @param encryptedFileStream destination file path
* @param sourceFilePath source file path
* @param partnerPublicKeyStream public key to encrypt
* @param secretKeyStream secret key to sign
* @param armor armor
* @param withIntegrityCheck integrity check
* @param pass pass phrase for secret key
* @throws IOException exception when performing file operations
* @throws NoSuchProviderException exception when provider not found
* @throws NoSuchAlgorithmException exception when generating signature
* @throws PGPException exception while encryption
* @throws SignatureException exception when unable to update signature
*/
public
static
void
encryptAndSignFile
(
OutputStream
encryptedFileStream
,
String
sourceFilePath
,
InputStream
partnerPublicKeyStream
,
InputStream
secretKeyStream
,
boolean
armor
,
boolean
withIntegrityCheck
,
char
[]
pass
)
throws
IOException
,
NoSuchProviderException
,
NoSuchAlgorithmException
,
PGPException
,
SignatureException
{
Security
.
addProvider
(
new
BouncyCastleProvider
());
PGPSecretKey
secretKeyToSign
=
readSecretKey
(
secretKeyStream
);
PGPPublicKey
partnerPublicKey
=
readPublicKey
(
partnerPublicKeyStream
);
if
(
armor
)
{
encryptedFileStream
=
new
ArmoredOutputStream
(
encryptedFileStream
);
}
PGPEncryptedDataGenerator
encryptedDataGenerator
=
new
PGPEncryptedDataGenerator
(
PGPEncryptedData
.
CAST5
,
withIntegrityCheck
,
new
SecureRandom
(),
"BC"
);
encryptedDataGenerator
.
addMethod
(
partnerPublicKey
);
OutputStream
encryptedOut
=
encryptedDataGenerator
.
open
(
encryptedFileStream
,
new
byte
[
10000
]);
PGPCompressedDataGenerator
comData
=
new
PGPCompressedDataGenerator
(
PGPCompressedData
.
ZIP
);
try
(
OutputStream
compressedData
=
comData
.
open
(
encryptedOut
))
{
PGPPrivateKey
pgpPrivKey
=
secretKeyToSign
.
extractPrivateKey
(
pass
,
"BC"
);
PGPSignatureGenerator
sGen
=
new
PGPSignatureGenerator
(
secretKeyToSign
.
getPublicKey
().
getAlgorithm
(),
PGPUtil
.
SHA1
,
"BC"
);
sGen
.
initSign
(
PGPSignature
.
BINARY_DOCUMENT
,
pgpPrivKey
);
Iterator
it
=
secretKeyToSign
.
getPublicKey
().
getUserIDs
();
if
(
it
.
hasNext
())
{
PGPSignatureSubpacketGenerator
spGen
=
new
PGPSignatureSubpacketGenerator
();
spGen
.
setSignerUserID
(
false
,
(
String
)
it
.
next
());
sGen
.
setHashedSubpackets
(
spGen
.
generate
());
}
sGen
.
generateOnePassVersion
(
false
).
encode
(
compressedData
);
// bOut
File
file
=
new
File
(
sourceFilePath
);
PGPLiteralDataGenerator
lGen
=
new
PGPLiteralDataGenerator
();
try
(
OutputStream
lOut
=
lGen
.
open
(
compressedData
,
PGPLiteralData
.
BINARY
,
file
.
getName
(),
new
Date
(),
new
byte
[
10000
]))
{
try
(
FileInputStream
fIn
=
new
FileInputStream
(
file
))
{
int
ch
;
while
((
ch
=
fIn
.
read
())
>=
0
)
{
lOut
.
write
(
ch
);
sGen
.
update
((
byte
)
ch
);
}
}
}
lGen
.
close
();
sGen
.
generate
().
encode
(
compressedData
);
comData
.
close
();
}
encryptedOut
.
close
();
encryptedDataGenerator
.
close
();
if
(
armor
)
{
encryptedFileStream
.
close
();
}
}
}
src/main/resources/application.properties
View file @
a703b7c8
files.directory.path
=
/Users/adanish/Documents/GitHub/Gap Repos/myazurefunctionsdemo/src/main/resources/files/
files.directory.path
=
/Users/eali/Projects/azure/myazurefunctionsdemo/src/main/resources/files/
\ No newline at end of file
encrypted.files.directory.path
=
/Users/eali/Projects/azure/myazurefunctionsdemo/src/main/resources/encrypted/
decrypted.files.directory.path
=
/Users/eali/Projects/azure/myazurefunctionsdemo/src/main/resources/decrypted/a.csv
gpg.keychain.public.key
=
/Users/eali/Projects/azure/myazurefunctionsdemo/src/main/resources/keys/gappocPublic.asc
gpg.keychain.secret.key
=
/Users/eali/Projects/azure/myazurefunctionsdemo/src/main/resources/keys/gappoc.asc
src/main/resources/keys/gappoc.asc
0 → 100644
View file @
a703b7c8
-----BEGIN PGP PRIVATE KEY BLOCK-----
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
GOZWWua17KtDIL4yx3hP
=wJXX
-----END PGP PRIVATE KEY BLOCK-----
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
=PJ5t
-----END PGP PUBLIC KEY BLOCK-----
src/main/resources/keys/gappocPublic.asc
0 → 100644
View file @
a703b7c8
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
=PJ5t
-----END PGP PUBLIC KEY BLOCK-----
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment