PGP signature format reader - java

In my project I need to verify PGP clear signed signatures using a corresponding public key. While I did manage to find a code which does that (For example: https://github.com/cjmalloy/openbitpub/blob/64485d64a699eb6096f01b27d5f7e51dd726602f/src/main/java/com/cjmalloy/obp/server/pgp/PgpUtil.java), it operates on a low level and looks pretty horrible.
I was thinking, perhaps there exist some specialized parsers that can consume -----BEGIN PGP PUBLIC KEY BLOCK-----xxx-----END PGP PUBLIC KEY BLOCK----- and -----BEGIN PGP SIGNED MESSAGE-----xxx-----BEGIN PGP SIGNATURE-----xxx-----END PGP SIGNATURE----- blocks so I can check signatures in a more declarative way?
I've found related PEMReader class from bouncycastle.openssl package but nothing PGP-related so far.

I was thinking, perhaps there exist some specialized parsers that can consume -----BEGIN PGP PUBLIC KEY BLOCK-----xxx-----END PGP PUBLIC KEY BLOCK----- and -----BEGIN PGP SIGNED MESSAGE-----xxx-----BEGIN PGP SIGNATURE-----xxx-----END PGP SIGNATURE----- blocks so I can check signatures in a more declarative way?
A parser will not be enough at all -- you will need to implement lots of OpenPGP-specific functions like symmetric key derivation from strings (for encrypted keys), handling of different types of assymetric cryptography algorithms, hash sums, different kinds of packet nesting, ... -- at least you're not required to implement the OpenPGP CBC mode deriate as you don't require encryption (only signatures).
OpenPGP is much to complicated to write your own parser and crypto code, rely on existing libraries instead. In the end, with Java you've got two possible roads to follow:
Using GnuPG through GPGME's Java interface, which requires a local GnuPG installation.
Using Bouncy Castle for Java which has a pretty much complete OpenPGP implementation in native Java code, but will require you to perform all the crypto operations in Java. The documentation pretty much consists of the JavaDoc for the OpenPGP package.
I've found related PEMReader class from bouncycastle.openssl package but nothing PGP-related so far.
You probably looked in the wrong BouncyCastle package. OpenPGP does not use keys in PEM format (which belongs to the X.509 standard), so this class will not be useful at all.

I came through the same situation sometimes back.
This was resolved by using the bouncy castle dependency and by using the method
decryptAndVerify(InputStream in, OutputStream fOut, InputStream publicKeyIn, InputStream keyIn, char[] passwd)
in PGP util class

The commercial OpenPGP Library for Java offers a convenient API for verifying clear text signatures. Sample code is:
import com.didisoft.pgp.*;
public class VerifyFile {
public static void main(String[] args) throws Exception{
// create an instance of the library
PGPLib pgp = new PGPLib();
// verify and extract the signed content
SignatureCheckResult signatureCheck = pgp.verifyAndExtract("signed.pgp", "sender_public_key.asc", "OUTPUT.txt");
if (signatureCheck == SignatureCheckResult.SignatureVerified) {
System.out.println("The signature is valid.");
} else if (signatureCheck == SignatureCheckResult.SignatureBroken) {
System.out.println("Message corrupted or signature forged");
} else if (signatureCheck == SignatureCheckResult.PublicKeyNotMatching) {
System.out.println("Signature not matching provided public key (the message is from another sender)");
} else {
System.out.println("No signature found in message");
}
}
}
Disclaimer: I work for DidiSoft.

Related

Is there any way to get the plain text from signed data using private key?

The plain text is signed using java.security.Signature. Below is the code used to sign the plain text
public String getSignature(String plainText) throws Exception
{
KeyStore keyStore = loadKeyStore(); // A local method to read the keystore file from file system.
PrivateKey privateKey = (PrivateKey) keyStore.getKey(KEY_ALIAS_IN_KEYSTORE, KEYSTORE_PASSWORD.toCharArray());
Signature privateSignature = Signature.getInstance(SIGNATUREALGO);
privateSignature.initSign(privateKey);
privateSignature.update(plainText.getBytes("UTF-8"));
byte[] signature = privateSignature.sign();
return String.valueOf(signature);
// KEY_ALIAS_IN_KEYSTORE, KEYSTORE_PASSWORD and SIGNATUREALGO are all constant Strings
}
Note 1: I found online a way to verify the signature using the public key Java Code Examples for java.security.Signature#verify(). But this is not what I require.
Note 2: I also found a ways to encrypt and decrypt as mentioned here RSA Signing and Encryption in Java. But the use case I have in hand is to get the original plain text from a signed data. Is that possible?
No, you can't retrieve the original content from just the signature.
The signature alone does not contain enough information to restore the original clear text, no matter what keys you have access to.
The basic idea of a signature is to send it together with the clear text. That means the clear text will be visible, but the signature can be used to verify that the message was written (or at least signed) by who claims to have done so and has not been tampered with since then.
Signing something is different from encrypting it. The two often uses the same or related technologies and both fall under cryptography.

how to implement encrpytion and decryption on a string

i want to encrypt a string to make data that is being stored secure, how would i do this. the code is found below. i am new to programming and encryption therefore need help on how to actually encrypt data that is being saved if anyone can guide please?
public class Utilities {
public static final String FILE_EXTENSION = ".bin";
public static boolean saveNote(Context context, Notes notes){
String fileName = String.valueOf(notes.getDateTime()) + FILE_EXTENSION;
not sure if the code provided is sufficient enough to see how to add encryption to a string which is "filename". how would i be able to implement encrypt/decrypt on that?
for simple encryption you can use base64 encoding and decoding. but if you want to high level security you can go with encryption and decryption algorithm like RC4, RC6, RSA, ECC, or AES and many more. for this you can use following java libraries :-
java.security
javax.crypto

Why does the Java KeyStore fail at loading an OpenPGP key?

I am willing to spend some amount of time developing yet another license manager for desktop Java application. After some looking around I discovered JCPUID by Iakin that is free to use and should work at most operating systems with native libs that I found here.
My idea is to do two modules: main application that will show popup window with CPU ID and verification text field and key generator app. User will pass CPU ID to keygen owner, who will return verification code (generated with keygen) to user. After user submits correct verification code, license file with that code will be created at filesystem. Every time the application starts up, it will check the existence and correctness of that file and load main application screen after that.
What about code verification, I think the best option will be to use asymmetric cryptography, in particular RSA. The public key will be built-in into application and secret will be built-in into key generator. So CPUID will be passed to key generator owner and then signed with RSA. That signature will be transferred back to user, who will verify its validity with built-in public key.
I generated gpg key pairs using Kleopatra and gpg Linux command line tool itself. Then I tried to sign something using this method:
private byte[] createSignature(byte[] file) {
byte[] signature = null;
try {
java.security.KeyStore keyStoreFile = java.security.KeyStore
.getInstance("PKCS12");
keyStoreFile.load(getClass().getClassLoader().getResourceAsStream("/secret.asc"),
"******".toCharArray());
PrivateKey privateKey = (PrivateKey) keyStoreFile.getKey(
"My Name Here", "******".toCharArray());
Signature dsa = Signature.getInstance("SHA1withRSA");
dsa.initSign(privateKey);
dsa.update(file, 0, file.length);
signature = dsa.sign();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return signature;
}
But the privateKey initialization throws exception:
java.security.InvalidKeyException: Key must not be null
I guess it's because of wrong instance format here:
java.security.KeyStore keyStoreFile = java.security.KeyStore
.getInstance("PKCS12");
I would like to know:
How good is this approach at all?
What difference exists between different OpenPGP key formats and which will be the best to use at this case? How to know the format of existing OpenPGP file?
The Java crypto framework does not support OpenPGP. X.509 keys, for example in the PKCS12 format, are incompatible with OpenPGP -- although they rely on (mostly) the same cryptographic algorithms.
Either use X.509 certificates (you could also create your own CA for this purpose), or rely on an implementation of OpenPGP for Java. In terms of open source libraries, you can choose between the native Java implementation BouncyCastle (MIT license), or interface GnuPG (GPL) through the Java GPGME binding (LGPL).
BouncyCastle is probably the better way to go, as all you need to do is add another Java library, not install another software into the system.

Veryfing signature generated by BouncyCastle on PC using native Java JCE

I am using BouncyCastle to generate a DSA signature but using the native JCE to verify the it.
NOTE: I am working with a j2me client that does not natively support signing hence the need for BouncyCastle)
So, on the client the signature is generated as follows:
DSASigner sig = new DSASigner();
sig.init(true, privateKey);
String plaintext = "This is the message being signed";
BigInteger[] sigArray = sig.generateSignature(plaintext.getBytes());
...
sigArray contains 2 BigIntegers r and s.
This signature then has to be transmitted to a server which uses native JCE to verify the sig. On the server side, using the native Java JCE, it should be possible to verify a signature as follows:
...
Signature sig = Signature.getInstance("SHA1withDSA");
byte[] sigbytes = Base64.decode(signature);
sig.initVerify(publicKey);
sig.update(plaintext.getBytes());
sig.verify(sigbytes)
The problem am having is: how do i encode sigArray into a format that can be sent to the pc/server as a single Base64 string (instead of separately as r and s) that can then be verified on the server using the native JCE method show in the second snippet of code?
So far i have tried to create DERObjects from the r,s arrays (separately, together as one array, encoded) but still no luck. Anybody faced this before? How did you tackle it?
According to Cryptographic Message Syntax Algorithms (RFC 3370) the DSA signature encoding is an ASN.1 sequence containing both integers r and s:
Dss-Sig-Value ::= SEQUENCE {
r INTEGER,
s INTEGER }

Reimplement AES encryption using third-party Java library without US law limitations

I've implemented AES encryption with certain task-specific parameters using standard Java tools and BouncyCastle provider for specific AES algorithm.
Here is the code:
private byte[] aesEncryptedInfo(String info) throws UnsupportedEncodingException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidParameterSpecException, InvalidAlgorithmParameterException, NoSuchProviderException {
Security.addProvider(new BouncyCastleProvider());
SecretKey secret = new SecretKeySpec(CUSTOMLONGSECRETKEY.substring(0, 32).getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");
cipher.init(Cipher.ENCRYPT_MODE, secret, new IvParameterSpec(VECTOR_SECRET_KEY.getBytes()));
return cipher.doFinal(info.getBytes("UTF-8"));
}
In some environments this code requires special policy files. See related question: InvalidKeyException Illegal key size
My goal is to reimplement it using third-party library, ideally I would use bouncy castle which is already used as provider. The library should have no restictions of standard java policy files. In other words there should be no restrictions.
Please suggest in your answers how to reimplement it using BouncyCastle or other third-party library which can work without restrictions mentioned. Ideally I would see the code :-)
Thank you very much for reading!
After a delay I now happy to post a solution. Hope that someone can benefit from it because Bouncy Castle documentation is not filled with a lot of examples :-)
private byte[] aesEncryptedInfo(String info)
// Creating AES/CBC/PKCS7Padding cipher with specified Secret Key and Initial Vector
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESEngine()), new PKCS7Padding());
cipher.init(true, new ParametersWithIV(new KeyParameter(CUSTOMLONGSECRETKEY.getBytes()), VECTOR_SECRET_KEY.getBytes()));
byte[] inputData = info.getBytes("UTF-8");
int outBlockSize = cipher.getOutputSize(inputData.length);
byte[] outputData = new byte[outBlockSize];
int outLength = cipher.processBytes(inputData, 0, inputData.length, outputData, 0);
outLength += cipher.doFinal(outputData, outLength);
if (outLength != outBlockSize) {
return Arrays.copyOf(outputData, outLength);
}
else {
return outputData;
}
}
By the way I found two differences between Java API and Bouncy Castle API:
1. Bouncy Castle uses composition of objects to create needed cipher. While Java API uses string to identify needed cipher.
2. BC encryption code slightly bigger, while Java API code is more compact.
The solution is full replacement for original Java API implementation - the proof is a custom unit test that I made.
Use the Bouncycastle lightweight crypto API directly, rather than through Java JCE interface. Bouncycastle includes its own crypto API accessible through various classes in org.bouncycastle.* packages. It also implements the JCE provider interface to make some of its crypto implementations available through standard JCE classes like Cipher, KeyGenerator, etc.
The cryptography policy restrictions are enforced by the JCE classes, not by bouncycastle. Therefore if you do not use these classes you'll will not encounter any restrictions. On the downside you will sacrifice some portability. To get started, take a look at the javadocs for the AESEngine class, and the rest of the javadocs for the bouncycastle.
Why isn't it possible to just add the necessary policy files?
That would be the easiest thing to do.
If you live in the US and you export your software to other (maybe "unallowed") countries, you will (theoretically) get trouble either way (including policy files/doing the encryption yourself).
If you live outside the US, why even bother about it, just include the policy files, no one cares.
No option for buying a toolkit? RSA BSAFE

Categories