I am becoming intermediate java programmer. I have tried hard to find out how to sign and read digital signatures in java for a net program i have been working on. I have been able to generate private and public keys with the tutorial at http://docs.oracle.com/javase/tutorial/security/apisign/index.html but have not been able to do anything with them. Although I know how to generate keys i didn't put it in because i wasn't sure if i had done them correctly.
Here is a simplified version of my code:
Main class:
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Scanner;
public class Main {
public static void main(String[] args) throws IOException {
Main main = new Main();
Scanner s = new Scanner(System.in);
while (true) {
//This is where i added a command detector so that the program can be in one class
System.out.println("Choose a command from the following:\nGenerate keys\nSign message\nRead message");
String command = s.nextLine();
if (command.equalsIgnoreCase("Generate key")
|| command.equalsIgnoreCase("Generate")) {
/* The code for generating the keys is here */
File f = new File("C:\\Users\\spencer\\Documents\\Stack ex\\src\\app","public.key");
File fi = new File("C:\\Users\\spencer\\Documents\\Stack ex\\src\\app","private.key");
if(!f.isFile()||!fi.isFile()) {
Make make =new Make();
Make.main(args);
}
else{
try {
String path = "C:\\Users\\spencer\\Documents\\ds test 3\\src\\app";
KeyPair loadedKeyPair = main.LoadKeyPair(path, "DSA");
System.out.println("Key pair already exists!");
System.out.println("Loaded Key Pair:");
main.dumpKeyPair(loadedKeyPair);
} catch (Exception e) {
e.printStackTrace();
return;
}
}
}
if (command.equalsIgnoreCase("Sign message")
|| command.equalsIgnoreCase("Sign")) {
long signature = 0;
System.out.println("What is your private key");
String pkey = s.nextLine();
long prkey = Long.parseLong(pkey);
System.out.println("What is you message");
String message = s.nextLine();
/* The code for signing the message goes here */
System.out.println("Signature:"+signature);
} else if (command.equalsIgnoreCase("Read message")
|| command.equalsIgnoreCase("Read")) {
String message = null;
System.out.println("What is the signature");
String sign = s.nextLine();
long signature = Long.parseLong(sign);
/* The code for reading the message goes here */
System.out.println(message);
}
}
}
private void dumpKeyPair(KeyPair keyPair) {
PublicKey pub = keyPair.getPublic();
System.out.println("Public Key: " + getHexString(pub.getEncoded()));
PrivateKey priv = keyPair.getPrivate();
System.out.println("Private Key: " + getHexString(priv.getEncoded()));
}
private String getHexString(byte[] b) {
String result = "";
for (int i = 0; i < b.length; i++) {
result += Integer.toString((b[i] & 0xff) + 0x100, 16).substring(1);
}
return result;
}
public KeyPair LoadKeyPair(String path, String algorithm)
throws IOException, NoSuchAlgorithmException,
InvalidKeySpecException {
// Read Public Key.
File filePublicKey = new File(path + "/public.key");
FileInputStream fis = new FileInputStream(path + "/public.key");
byte[] encodedPublicKey = new byte[(int) filePublicKey.length()];
fis.read(encodedPublicKey);
fis.close();
// Read Private Key.
File filePrivateKey = new File(path + "/private.key");
fis = new FileInputStream(path + "/private.key");
byte[] encodedPrivateKey = new byte[(int) filePrivateKey.length()];
fis.read(encodedPrivateKey);
fis.close();
// Generate KeyPair.
KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(
encodedPublicKey);
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(
encodedPrivateKey);
PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);
return new KeyPair(publicKey, privateKey);
}
}
Make class:
import java.io.*;
import java.security.*;
import java.security.spec.*;
public class Make {
public static void main(String args[]) {
Make adam = new Make();
try {
String path = "C:\\Users\\spencer\\Documents\\Stack ex\\src\\app";
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA");
keyGen.initialize(512);
KeyPair generatedKeyPair = keyGen.genKeyPair();
System.out.println("Generated Key Pair");
adam.dumpKeyPair(generatedKeyPair);
adam.SaveKeyPair(path, generatedKeyPair);
} catch (Exception e) {
e.printStackTrace();
return;
}
}
private void dumpKeyPair(KeyPair keyPair) {
PublicKey pub = keyPair.getPublic();
System.out.println("Public Key: " + getHexString(pub.getEncoded()));
PrivateKey priv = keyPair.getPrivate();
System.out.println("Private Key: " + getHexString(priv.getEncoded()));
}
private String getHexString(byte[] b) {
String result = "";
for (int i = 0; i < b.length; i++) {
result += Integer.toString((b[i] & 0xff) + 0x100, 16).substring(1);
}
return result;
}
public void SaveKeyPair(String path, KeyPair keyPair) throws IOException {
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();
// Store Public Key.
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(
publicKey.getEncoded());
FileOutputStream fos = new FileOutputStream(path + "/public.key");
fos.write(x509EncodedKeySpec.getEncoded());
fos.close();
// Store Private Key.
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(
privateKey.getEncoded());
fos = new FileOutputStream(path + "/private.key");
fos.write(pkcs8EncodedKeySpec.getEncoded());
fos.close();
}
}
I need a little help with signing and reading the signature.
Related
I have some code in Java that successfully verifies and sign messages with SHA256withRSA. However when I try to verify the same data with my c# code, I get a different signature and verification of the signature fails. As the SHA values match, i figure it not related to codepage. I tried multiple ways to figure this one out, but is yet to fail, so any ideas is more than welcome.
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.X509EncodedKeySpec;
import java.io.*;
import java.util.*;
import java.security.*;
import java.util.Base64;
import java.lang.*;
import java.nio.charset.*;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMException;
import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
public class Main {
public static void main(String[] args) throws Exception {
String privatePem = "c:\\Lab\\Cert\\private.pem";
String publicPem = "C:\\Lab\\Cert\\public.pem";
String datafile = "C:\\Lab\\Cert\\data.txt";
byte[] buf = Files.readAllBytes(Paths.get(datafile));
String message = new String(buf, StandardCharsets.UTF_8);
System.out.println("-----------------------------------------------------------------------------------------------------------------------------------------");
System.out.println("Message to sign:");
System.out.println(message);
System.out.println("-----------------------------------------------------------------------------------------------------------------------------------------");
PrivateKey privateKey = PrivateKeyReader(privatePem).getPrivate();
PublicKey publicKey = get(publicPem);
// Get SHA-256
byte[] messageAsByte = message.getBytes(Charset.forName( "UTF-8" ));
byte[] sha256OfMessage = digestSha256(messageAsByte);
byte[] sha512OfMessage = digestSha512(messageAsByte);
byte[] base64encodedSha256 = Base64.getEncoder().encode(sha256OfMessage);
byte[] base64encodedSha512 = Base64.getEncoder().encode(sha512OfMessage);
String Sha256ContentDigest = new String(base64encodedSha256, StandardCharsets.UTF_8);
String Sha512ContentDigest = new String(base64encodedSha512, StandardCharsets.UTF_8);
byte[] signature256 = generateSignature256(messageAsByte, privateKey);
String sig25664 = Base64.getEncoder().encodeToString(signature256);
System.out.println("X-Content-Digest: SHA256 " + Sha256ContentDigest);
System.out.println("X-Signature: RSA-SHA256 " + sig25664);
System.out.println("-----------------------------------------------------------------------------------------------------------------------------------------");
byte[] signature512 = generateSignature512(messageAsByte, privateKey);
String sig51264 = Base64.getEncoder().encodeToString(signature512);
System.out.println("X-Content-Digest: SHA512 " + Sha512ContentDigest);
System.out.println("X-Signature: RSA-SHA512 " + sig51264);
System.out.println("-----------------------------------------------------------------------------------------------------------------------------------------");
System.out.println("Signature verification SHA256: " + verifySignature256(messageAsByte, sha256OfMessage, signature256, publicKey));
System.out.println("Signature verification SHA512: " + verifySignature512(messageAsByte, sha512OfMessage, signature512, publicKey));
System.out.println("-----------------------------------------------------------------------------------------------------------------------------------------");
}
private static KeyPair PrivateKeyReader(String keyPath) {
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader(keyPath));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
Security.addProvider(new BouncyCastleProvider());
PEMParser pp = new PEMParser(br);
PEMKeyPair pemKeyPair = null;
try {
pemKeyPair = (PEMKeyPair) pp.readObject();
} catch (IOException e) {
e.printStackTrace();
}
try {
KeyPair kp = new JcaPEMKeyConverter().getKeyPair(pemKeyPair);
return kp;
} catch (PEMException e) {
e.printStackTrace();
}
try {
pp.close();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static byte[] generateSignature256(byte[] requestMessage, PrivateKey privateKey) throws Exception {
byte[] contentDigest = digestSha256(requestMessage);
Signature signature = Signature.getInstance("Sha256withRSA");
signature.initSign(privateKey);
signature.update(contentDigest);
return signature.sign();
}
public static byte[] generateSignature512(byte[] requestMessage, PrivateKey privateKey) throws Exception {
byte[] contentDigest = digestSha512(requestMessage);
Signature signature = Signature.getInstance("Sha512withRSA");
signature.initSign(privateKey);
signature.update(contentDigest);
return signature.sign();
}
public static boolean verifySignature256(byte[] requestMessage, byte[] requestContentDigest, byte[] requestSignature, PublicKey publicKey) throws Exception {
byte[] contentDigest = digestSha256(requestMessage);
if (!Arrays.equals(requestContentDigest, contentDigest)) {
return false;
}
Signature signature = Signature.getInstance("Sha256withRSA");
signature.initVerify(publicKey);
signature.update(contentDigest);
return signature.verify(requestSignature);
}
public static boolean verifySignature512(byte[] requestMessage, byte[] requestContentDigest, byte[] requestSignature, PublicKey publicKey) throws Exception {
byte[] contentDigest = digestSha512(requestMessage);
if (!Arrays.equals(requestContentDigest, contentDigest)) {
return false;
}
Signature signature = Signature.getInstance("Sha512withRSA");
signature.initVerify(publicKey);
signature.update(contentDigest);
return signature.verify(requestSignature);
}
public static byte[] digestSha256(byte[] requestMessage){
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
return digest.digest(requestMessage);
} catch (Exception e){
return null;
}
}
public static byte[] digestSha512(byte[] requestMessage){
try {
MessageDigest digest = MessageDigest.getInstance("SHA-512");
return digest.digest(requestMessage);
} catch (Exception e){
return null;
}
}
public static PublicKey get(String keyPath)
throws Exception {
Reader reader = new FileReader(keyPath);
PublicKey key;
try {
org.bouncycastle.util.io.pem.PemObject spki = new org.bouncycastle.util.io.pem.PemReader(reader).readPemObject();
key = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(spki.getContent()));
} catch (Exception ex) {
FileInputStream fin = new FileInputStream(keyPath);
CertificateFactory f = CertificateFactory.getInstance("X.509");
X509Certificate certificate = (X509Certificate)f.generateCertificate(fin);
key = certificate.getPublicKey();
}
return key;
}
}
Output:
-----------------------------------------------------------------------------------------------------------------------------------------
Message to sign:
abc123
-----------------------------------------------------------------------------------------------------------------------------------------
X-Content-Digest: SHA256 bKE9UspwyIPg8LsQHkJaiehiTeUdstI5JZOvaoQRgJA=
X-Signature: RSA-SHA256 H9DF4NYV9YOZ3B3iogDIdlTzzQpKGWniQNHF5ZxladLes0MDcFopUSzyO6XiO1Y/AVBGLK18iq2nCc8ho+fXb6c4V08/PSE4lrGJu7z8dAs9UwodDgAx3+TXBV8iNkGtj3XThy7QhvruPA0txRLgdaRmKSJsBSoR7HK6LC0ES2LYzypQFXuQ+4LInWETPc4Ttp9bgSf/h07bZaQMlbO29hIQXZc31WCVTGmsJOG+TMBdF+CpWF04sj12ThR539VCpGrJRrE6xsYSg2VQMgo9t2XkcC/nn3Z4FOMD4o5yuwjHHJO1Hs4wyZfpSehIT96pYwvhkyMM5fS0Ms/Po9WUUg==
-----------------------------------------------------------------------------------------------------------------------------------------
X-Content-Digest: SHA512 xwtd2ev7b1HQnUEytxcMnSB1CnhS8AaA9lZY8DEOgQBW5nY8NMmgCw6UAHb1RJXBafwjAszrMSA5JxxDRpUH3A==
X-Signature: RSA-SHA512 UT0UlWI06+pYg+OuJGCaoIua23lq/k3yATkO9wQOl7BGLO56t7dvVZQz8UYtzIUhTrDktw9McqyTncDH8bZKMNMMCPLR7K3xAe3gCgipYE8VSP8uVeLDlqKhc/4OO+HDL6T6L44L1dwy5jKBVbVxDDKib7b0lLtTUtTHIh9WOX74hF6P3OiAZ8CD7tJg4QjngJ0GcM9WKXzfDNxVnOzGkhSarhCu3vsUP7QwG2um54uaADgqcJoJvVVyhlwOPF4kPH8SaAPItUIbz46h4bpF182YFZ7QJeg8TmsqXeOdO2MPdKOPYQsPfwZVs/UFkl7Z0oC5WE9UX7Ds9B7/VkOudw==
-----------------------------------------------------------------------------------------------------------------------------------------
Signature verification SHA256: true
Signature verification SHA512: true
-----------------------------------------------------------------------------------------------------------------------------------------
.Net C# code attempt:
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
namespace VAS
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("-----------------------------------------------------------------------------------------------------------------------------------------");
byte[] messageAsByte = File.ReadAllBytes(#"C:\Lab\Cert\data.txt");
Console.WriteLine("Message to sign:");
Console.WriteLine(Encoding.UTF8.GetString(messageAsByte));
Console.WriteLine("-----------------------------------------------------------------------------------------------------------------------------------------");
var publicKey = LoadPublicKey(#"C:\Lab\Cert\public.pem");
var privateKey = LoadPrivateKey(#"C:\Lab\Cert\private.pem");
var sha256OfMessage = digestSha256(messageAsByte);
var sha512OfMessage = digestSha512(messageAsByte);
string Sha256ContentDigest = Convert.ToBase64String(sha256OfMessage);
string Sha512ContentDigest = Convert.ToBase64String(sha512OfMessage);
HashAlgorithm hash256Algorith = SHA256Managed.Create();
HashAlgorithm hash512Algorith = SHA256Managed.Create();
byte[] sig256 = privateKey.SignData(messageAsByte, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
byte[] sig512 = privateKey.SignData(messageAsByte, HashAlgorithmName.SHA512, RSASignaturePadding.Pkcs1);
var sig64256 = Convert.ToBase64String(sig256);
var sig64512 = Convert.ToBase64String(sig512);
Console.WriteLine("X-Content-Digest: SHA256 " + Sha256ContentDigest);
Console.WriteLine("X-Signature: RSA-SHA256 " + sig64256);
Console.WriteLine("-----------------------------------------------------------------------------------------------------------------------------------------");
Console.WriteLine("X-Content-Digest: SHA512 " + Sha512ContentDigest);
Console.WriteLine("X-Signature: RSA-SHA512 " + sig64512);
Console.WriteLine("-----------------------------------------------------------------------------------------------------------------------------------------");
var verify256 = publicKey.VerifyData(messageAsByte, CryptoConfig.MapNameToOID("SHA256"), sig256);
var verify512 = publicKey.VerifyData(messageAsByte, CryptoConfig.MapNameToOID("SHA512"), sig512);
Console.WriteLine("Signature verify 256: " + verify256);
Console.WriteLine("Signature verify 512: " + verify512);
Console.ReadKey();
}
public static RSACryptoServiceProvider LoadPublicKey(String path)
{
System.IO.StreamReader fileStream = File.OpenText(path);
PemReader pemReader = new PemReader(fileStream);
AsymmetricKeyParameter KeyParameter = (AsymmetricKeyParameter)pemReader.ReadObject();
RSAParameters rsaParams = DotNetUtilities.ToRSAParameters((RsaKeyParameters)KeyParameter);
RSACryptoServiceProvider csp = new RSACryptoServiceProvider();// cspParams);
csp.ImportParameters(rsaParams);
return csp;
}
public static RSACryptoServiceProvider LoadPrivateKey(String path)
{
System.IO.StreamReader fileStream = File.OpenText(path);
PemReader pemReader = new PemReader(fileStream);
AsymmetricCipherKeyPair KeyParameter = (AsymmetricCipherKeyPair)pemReader.ReadObject();
RSAParameters rsaParams = DotNetUtilities.ToRSAParameters((RsaPrivateCrtKeyParameters)KeyParameter.Private);
RSACryptoServiceProvider csp = new RSACryptoServiceProvider();// cspParams);
csp.ImportParameters(rsaParams);
return csp;
}
public static byte[] digestSha256(byte[] requestMessage)
{
SHA256Managed shHash = new SHA256Managed();
return shHash.ComputeHash(requestMessage);
}
public static byte[] digestSha512(byte[] requestMessage)
{
SHA512Managed shHash = new SHA512Managed();
return shHash.ComputeHash(requestMessage);
}
}
}
Output:
-----------------------------------------------------------------------------------------------------------------------------------------
Message to sign:
abc123
-----------------------------------------------------------------------------------------------------------------------------------------
X-Content-Digest: SHA256 bKE9UspwyIPg8LsQHkJaiehiTeUdstI5JZOvaoQRgJA=
X-Signature: RSA-SHA256 Wo0dFOfzAJJZTb4zpOHkPVdpgWS1K2Q5IdAAD1wQ+w1veAIbmu+XByBHAbme0PiazdqF6QokFm9IudF7NmyqNjNybIKSuTRPUiP474/kliQl7lDiJJoFejBIaVwQhHdds0CkomZZPulZZSYuIi7cqODaKCXxe/Js9tm/htMu3Wd6nejgaoMX3TGXHWyE6ixJI8Zq7ysD6yjksIWlYthsd0WmCR6mVTKR9zo7BiVPxYsOcJ7MFLSvyJgHHoFmXG9KBZhcA1rx8RquvWLGKxU+WWbt7u/9OqY+HKGPCPo2/S1xmdTP2kiVp1zhQ0JQ4uBgP9nkNqrBxh3QzSZgsCbJKg==
-----------------------------------------------------------------------------------------------------------------------------------------
X-Content-Digest: SHA512 xwtd2ev7b1HQnUEytxcMnSB1CnhS8AaA9lZY8DEOgQBW5nY8NMmgCw6UAHb1RJXBafwjAszrMSA5JxxDRpUH3A==
X-Signature: RSA-SHA512 V47yMVpBunwkUVz0lmi5ZJkYkj2+C9V3YX1MB7OaDvobCGc9F0vBoEsxsV0sDIR2gZsHVMowXFU2bHzIoNdeGz+iyichQ89fJXYP+qPQUZO42t0UXfefX/9LlMbkGlzOqFvfBkcOFidhF9x36ZGPcC6C9AjOC7r1sqL/IBxNENuknhcbBMzHHpJZXFzVo09U/p7LIs3kJxAE9TLkR4ir2syAfisKrbJYCTSZnwm38ikR35mMmigme8eByE6GuOmizshv7lrtd4K5d0RA1jWM1TrNKpLqil4IWbrYQXZCBnHUmLH4fTD7aGIpM+SxQXLBV/lDhWA3O8vXDdFnW0llxQ==
-----------------------------------------------------------------------------------------------------------------------------------------
Signature verify 256: True
Signature verify 512: True
Testkeys and data
private.pem:
-----BEGIN RSA PRIVATE KEY-----
MIIEoQIBAAKCAQBk04fDxgG0eV/b7wcTYK7kq72w4YMzlPyBy6hERHWD2DhuM6TQ
MF7cafxc4b8krGMBqgV9m7AQxhWn4GCmCHljacXivTc1qBp3S54IitZFqvyGhnC0
dqKshqaL6z/S1kbiPZmiiXpZScYkje5pxY7k11PTopqnV9/g89Cu+PDEd7KcA0XE
XbYaEZtufvahZBmbF5mQPAr5YwGDgrR16CiAGi3dcWqX7g7AJb6bSJQp1SEWYVHU
klSdOtIJPgTDB57VIC8klKJ0c2Lnn3M+qPl6aD0qLTyl2QH1q97G+7E0e2dYAAbX
j0uU8753iEE/nHeOz09ACkIdLw9e97Kmka4DAgMBAAECggEAV9DE1oaGxaFRFEVD
bGUw7omGVaCUnUCODJ5Ml+joUUTpIVJpocn/VQoaeutDh7V9Jd3nmlcXKgTcp7KN
ew62axec+rbCd0FKi8yYf+gsZ9Fcz+4YC5WoaYt9UzA6DnACnNn6Dc6feVT/9qaH
mCgxJK9Gm3VsLYQjwdGZWEwJp5NhBXDHMAPIKJqGfI6v3XI3DOa/VPy4zCMrwMpb
Pps0NOMXiwOmWlDVZsDdc36/oICHpib3qHH9Crgbo4i3hDiCCnC97fJiZW6FjfiJ
TtXAIPDAfMIW/etLD6lI9O0s3IbcRf4GjnkmM/JMaJnV9mqqN4Nrn57uDyUC5Ged
2/v6gQKBgQCpWGSe16bFYZQsZunJAcdRGqoj0o3dCb3HpB1pnnKdahIsBYguLlnm
y2QaVXuFPOUMkRfrOGDITP4hSUiN0hsFT1uThE5IsT4u2KdUe2kSlgWerihPWfuZ
UO5w0ag3mgv4avUlg9/wAlRbq7L9s+QivnNxsR6aSuyb+cqLWW8WuQKBgQCYa2bp
FTWO5MDRxia4rHvcj+/4bt7zFwX1JUwfbFR8VtUul/Wk5w2JnzEQgF+Td7gJJxv8
u4JJxZNh8TOqek58lyg1KQKSod8mp8CnW9A2utU2MapZsCxyY7T1jgmXVvcXCQ3W
eJs1VpgQnoZxbzqbV9muQWjQRCCSR/WQ6hBMmwKBgG7G8vNxkJe30E0HeVFTR4ZH
khri5og8khfhxJfN3Z4ZwA9qAv5qtcajMDWFy8qJ3i/NTj9B3xXIP8mYfczAL4rW
scobF3a38zyD31oFbOOKndyCgr391/cgGQpWK9tLex8jIIBM9xWzAGoDNJB/t/H+
cdhii+lUr9kMmzFy7JeJAoGABR3V3o0vtxRGxMP6GMjxf331eEmAgniLYqdV3tgs
HeBsV5wSSu7WrYACjaNBkhm6u9PsRJem0AMp52fJbDee2t/YIbC2vWVhsFKBTRzv
6GZtMdyI82nOlCh0sqmJ+OKaeNN8+24hB7FYeXZY3QX22bAhRpA7jII89awkujCh
S3ECgYBNdGKf5NXxL1n//7GlBsH8sIyNUnHN4dQOORPdSSsynqDcpbdkRFkBIioF
5Q70DOhyS69F8Yu4d1qr09E7AbFpMmQjieDwzdZ6z0b9WInbcKo71FqCaZzz8azt
AMG22E827GX9z7F207rPf7GWpvhpGjzbxHXGXSEyFy2CvetpAA==
-----END RSA PRIVATE KEY-----
public.pem:
-----BEGIN PUBLIC KEY-----
MIIBITANBgkqhkiG9w0BAQEFAAOCAQ4AMIIBCQKCAQBk04fDxgG0eV/b7wcTYK7k
q72w4YMzlPyBy6hERHWD2DhuM6TQMF7cafxc4b8krGMBqgV9m7AQxhWn4GCmCHlj
acXivTc1qBp3S54IitZFqvyGhnC0dqKshqaL6z/S1kbiPZmiiXpZScYkje5pxY7k
11PTopqnV9/g89Cu+PDEd7KcA0XEXbYaEZtufvahZBmbF5mQPAr5YwGDgrR16CiA
Gi3dcWqX7g7AJb6bSJQp1SEWYVHUklSdOtIJPgTDB57VIC8klKJ0c2Lnn3M+qPl6
aD0qLTyl2QH1q97G+7E0e2dYAAbXj0uU8753iEE/nHeOz09ACkIdLw9e97Kmka4D
AgMBAAE=
-----END PUBLIC KEY-----
data.txt:
abc123
I also tried signing with OpenSSL, and that gives the same result i get with C#. Any help would be appricated so I can handle the data that is generated in Java.
Thanks!
The difference is in handling the hash. In .NET you are handling it correctly:
byte[] sig256 = privateKey.SignData(messageAsByte, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
however in Java, for some reason, you are feeding a precomputed hash value instead of the data:
byte[] contentDigest = digestSha256(requestMessage);
...
signature.update(contentDigest);
In other words, your data is hashed, and then the hash over the data is hashed.
Remember that signature generation in general includes the hashing of the data. Sometimes you can feed a precomputed hash value into the signature generation / verification, but commonly you'll have to call a specifically named method for that, calls such as update are for the message data itself.
Both .NET and Java use PKCS#1 v1.5 padding in your code snippets. PKCS#1 v1.5 padding for signature generation is indeed deterministic and considered secure. PSS is a newer, non-deterministic and more secure method and should be preferred for new protocols & applications.
As a small bonus, here is some code for testing:
private static final String PUB_BASE_64 = "MIIBITANBgkqhkiG9w0BAQEFAAOCAQ4AMIIBCQKCAQBk04fDxgG0eV/b7wcTYK7k" +
"q72w4YMzlPyBy6hERHWD2DhuM6TQMF7cafxc4b8krGMBqgV9m7AQxhWn4GCmCHlj" +
"acXivTc1qBp3S54IitZFqvyGhnC0dqKshqaL6z/S1kbiPZmiiXpZScYkje5pxY7k" +
"11PTopqnV9/g89Cu+PDEd7KcA0XEXbYaEZtufvahZBmbF5mQPAr5YwGDgrR16CiA" +
"Gi3dcWqX7g7AJb6bSJQp1SEWYVHUklSdOtIJPgTDB57VIC8klKJ0c2Lnn3M+qPl6" +
"aD0qLTyl2QH1q97G+7E0e2dYAAbXj0uU8753iEE/nHeOz09ACkIdLw9e97Kmka4D" +
"AgMBAAE=";
private static final String SIG_SHA256_DOTNET_BASE_64 = "Wo0dFOfzAJJZTb4zpOHkPVdpgWS1K2Q5IdAAD1wQ+w1veAIbmu+XByBHAbme0PiazdqF6QokFm9IudF7NmyqNjNybIKSuTRPUiP474/kliQl7lDiJJoFejBIaVwQhHdds0CkomZZPulZZSYuIi7cqODaKCXxe/Js9tm/htMu3Wd6nejgaoMX3TGXHWyE6ixJI8Zq7ysD6yjksIWlYthsd0WmCR6mVTKR9zo7BiVPxYsOcJ7MFLSvyJgHHoFmXG9KBZhcA1rx8RquvWLGKxU+WWbt7u/9OqY+HKGPCPo2/S1xmdTP2kiVp1zhQ0JQ4uBgP9nkNqrBxh3QzSZgsCbJKg==";
private static final String SIG_SHA256_JAVA_BASE_64 = "H9DF4NYV9YOZ3B3iogDIdlTzzQpKGWniQNHF5ZxladLes0MDcFopUSzyO6XiO1Y/AVBGLK18iq2nCc8ho+fXb6c4V08/PSE4lrGJu7z8dAs9UwodDgAx3+TXBV8iNkGtj3XThy7QhvruPA0txRLgdaRmKSJsBSoR7HK6LC0ES2LYzypQFXuQ+4LInWETPc4Ttp9bgSf/h07bZaQMlbO29hIQXZc31WCVTGmsJOG+TMBdF+CpWF04sj12ThR539VCpGrJRrE6xsYSg2VQMgo9t2XkcC/nn3Z4FOMD4o5yuwjHHJO1Hs4wyZfpSehIT96pYwvhkyMM5fS0Ms/Po9WUUg==";
public static void main(String[] args) throws Exception {
KeyFactory rsaKeyFactory = KeyFactory.getInstance("RSA");
PublicKey pub = rsaKeyFactory.generatePublic(new X509EncodedKeySpec(Base64.getDecoder().decode(PUB_BASE_64)));
Cipher rsa = Cipher.getInstance("RSA/ECB/NoPadding");
rsa.init(Cipher.DECRYPT_MODE, pub);
{
byte[] sig = Base64.getDecoder().decode(SIG_SHA256_JAVA_BASE_64);
byte[] plainSigJava = rsa.doFinal(sig);
System.out.println(Hex.toHexString(plainSigJava));
}
{
byte[] sig = Base64.getDecoder().decode(SIG_SHA256_DOTNET_BASE_64);
byte[] plainSigDotNet = rsa.doFinal(sig);
System.out.println(Hex.toHexString(plainSigDotNet));
}
byte[] hashSha256 = Base64.getDecoder().decode("bKE9UspwyIPg8LsQHkJaiehiTeUdstI5JZOvaoQRgJA=");
System.out.println(Hex.toHexString(hashSha256));
}
prints:
0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d060960864801650304020105000420efaaeb3b1d1d85e8587ef0527ca43b9575ce8149ba1ee41583d3d19bd130daf8
0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d0609608648016503040201050004206ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090
6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090
Note that the last signature "decryption" is the .NET one and contains the right hash value, printed on the final line.
Sorry, I used a non-standard Hex decoder, the rest is plain Java that you can put in a class definition.
I need to store sensitive datas (little string) into the keystore.
The example described here is pretty much exactly what I need to do.
Problem: I don't understand it very well, I'm totally newbie in that subject (Cipher, encryption, RSA...)
https://medium.com/#ericfu/securely-storing-secrets-in-an-android-application-501f030ae5a3#.oqvxbjn8m
So this is the class that I'm working on (based on this article mentioned here above) :
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.security.KeyPairGeneratorSpec;
import android.security.keystore.KeyProperties;
import android.support.v7.app.AppCompatActivity;
import android.util.Base64;
import android.util.Log;
import android.widget.Toast;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Calendar;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.spec.SecretKeySpec;
import javax.security.auth.x500.X500Principal;
public class SecondActivity extends AppCompatActivity {
static final String TAG = "SimpleKeystoreApp";
static final String CIPHER_PROVIDER = "AndroidOpenSSL";
private static final String RSA_MODE = "RSA/ECB/PKCS1Padding";
private static final String AES_MODE = "AES/ECB/PKCS7Padding";
private static final String KEY_ALIAS = "this is my alias";
private static final String SHARED_PREFENCE_NAME = "my shared_prefs";
private static final String ENCRYPTEDKEY_KEY = "encrypted_key";
private static final String TO_BE_ENCRYPTED_KEY = "this is my test";
private static final String ANDROID_KEYSTORE = "AndroidKeyStore";
KeyStore keyStore;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
keyStore = KeyStore.getInstance(ANDROID_KEYSTORE);
keyStore.load(null);
} catch (Exception e) {
Log.d(TAG, e.getMessage());
}
createNewKeys();
try {
generateAndStoreAESKey();
} catch (Exception e) {
Log.d(TAG, "couldn't generateAndStoreAESKey:" + e.getMessage());
}
String encrypted = null;
try {
encrypted = encrypt(getApplicationContext(), TO_BE_ENCRYPTED_KEY.getBytes());
Log.d(TAG, "encrypted:" + encrypted);
} catch (Exception e) {
Log.d(TAG, "couldn't encrypt:" + e.getMessage());
}
try {
decrypt(getApplicationContext(), encrypted.getBytes());
Log.d(TAG, "decrypted:" + encrypted);
} catch (Exception e) {
Log.d(TAG, "couldn't decrypt:" + e.getMessage());
}
setContentView(R.layout.activity_main);
}
public void createNewKeys() {
Log.d(TAG, "___ createNewKeys");
try {
// Create new key if needed
// Generate the RSA key pairs
keyStore = KeyStore.getInstance(ANDROID_KEYSTORE);
keyStore.load(null);
// Generate the RSA key pairs
if (!keyStore.containsAlias(KEY_ALIAS)) {
// Generate a key pair for encryption
Calendar start = Calendar.getInstance();
Calendar end = Calendar.getInstance();
end.add(Calendar.YEAR, 30);
KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(this)
.setAlias(KEY_ALIAS)
.setSubject(new X500Principal("CN=" + KEY_ALIAS))
.setSerialNumber(BigInteger.TEN)
.setStartDate(start.getTime())
.setEndDate(end.getTime())
.build();
KeyPairGenerator kpg = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, ANDROID_KEYSTORE);
kpg.initialize(spec);
kpg.generateKeyPair();
KeyPair keyPair = kpg.generateKeyPair();
Log.d(TAG, "Public Key is: " + keyPair.getPublic().toString());
}
} catch (Exception e) {
Toast.makeText(this, "Exception " + e.getMessage() + " occured", Toast.LENGTH_LONG).show();
Log.e(TAG, Log.getStackTraceString(e));
}
}
private void generateAndStoreAESKey() throws Exception{
Log.d(TAG, "___ generateAndStoreAESKey");
SharedPreferences pref = getApplicationContext().getSharedPreferences(SHARED_PREFENCE_NAME, Context.MODE_PRIVATE);
String enryptedKeyB64 = pref.getString(ENCRYPTEDKEY_KEY, null);
if (enryptedKeyB64 == null) {
byte[] key = new byte[16];
SecureRandom secureRandom = new SecureRandom();
secureRandom.nextBytes(key);
byte[] encryptedKey = rsaEncrypt(key);
enryptedKeyB64 = Base64.encodeToString(encryptedKey, Base64.DEFAULT);
SharedPreferences.Editor edit = pref.edit();
edit.putString(ENCRYPTEDKEY_KEY, enryptedKeyB64);
edit.commit();
}
}
private SecretKeySpec getSecretKey(Context context) throws Exception{
SharedPreferences pref = context.getSharedPreferences(SHARED_PREFENCE_NAME, Context.MODE_PRIVATE);
String enryptedKeyB64 = pref.getString(ENCRYPTEDKEY_KEY, null);
// need to check null, omitted here
byte[] encryptedKey = Base64.decode(enryptedKeyB64, Base64.DEFAULT);
byte[] key = rsaDecrypt(encryptedKey);
return new SecretKeySpec(key, "AES");
}
public String encrypt(Context context, byte[] input) throws Exception{
Cipher c = Cipher.getInstance(AES_MODE, "BC");
c.init(Cipher.ENCRYPT_MODE, getSecretKey(context));
byte[] encodedBytes = c.doFinal(input);
String encryptedBase64Encoded = Base64.encodeToString(encodedBytes, Base64.DEFAULT);
return encryptedBase64Encoded;
}
public byte[] decrypt(Context context, byte[] encrypted) throws Exception{
Cipher c = Cipher.getInstance(AES_MODE, "BC");
c.init(Cipher.DECRYPT_MODE, getSecretKey(context));
byte[] decodedBytes = c.doFinal(encrypted);
return decodedBytes;
}
private byte[] rsaEncrypt(byte[] secret) throws Exception{
KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry) keyStore.getEntry(KEY_ALIAS, null);
// Encrypt the text
Cipher inputCipher = Cipher.getInstance(RSA_MODE, CIPHER_PROVIDER);
inputCipher.init(Cipher.ENCRYPT_MODE, privateKeyEntry.getCertificate().getPublicKey());
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
CipherOutputStream cipherOutputStream = new CipherOutputStream(outputStream, inputCipher);
cipherOutputStream.write(secret);
cipherOutputStream.close();
byte[] vals = outputStream.toByteArray();
return vals;
}
private byte[] rsaDecrypt(byte[] encrypted) throws Exception {
KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry) keyStore.getEntry(KEY_ALIAS, null);
Cipher output = Cipher.getInstance(RSA_MODE, CIPHER_PROVIDER);
output.init(Cipher.DECRYPT_MODE, privateKeyEntry.getPrivateKey());
CipherInputStream cipherInputStream = new CipherInputStream(
new ByteArrayInputStream(encrypted), output);
ArrayList<Byte> values = new ArrayList<>();
int nextByte;
while ((nextByte = cipherInputStream.read()) != -1) {
values.add((byte)nextByte);
}
byte[] bytes = new byte[values.size()];
for(int i = 0; i < bytes.length; i++) {
bytes[i] = values.get(i).byteValue();
}
return bytes;
}
}
I have a InvalidKeyException: Need RSA private or public key being thrown when I call
outputCipher.init(Cipher.DECRYPT_MODE, privateKeyEntry.getPrivateKey());
in
private byte[] rsaDecrypt(byte[] encrypted)
So I need to be able to decrypt the private key stored in the keystore, but this operation gives me an error.
I don't understand why. Maybe there is something wrong in the flow?
Please explain me in simple words what I'm doing wrong.
#Robert answer in a comment resolved my issue:
I removed CIPHER_PROVIDER from
Cipher inputCipher = Cipher.getInstance(RSA_MODE, CIPHER_PROVIDER);
today, I wrote some code to encrypt a String with AES and encrypt the key with RSA. When I try to decrypt the everything, Java gives me a BadPaddingException.
Here is my code:
Test.java:
import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.SecretKeySpec;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.PrintWriter;
import java.security.Key;
import java.security.SecureRandom;
import java.util.Scanner;
public class Test {
private static String publicName = null;
private static String privateName = null;
public static void main(String[] args) throws Exception {
Scanner scanner = new Scanner(System.in);
System.out.println("Choose an option: \n(1) Decrypt \n(2) Encrypt \n(3) Generate Keypair");
int choice = scanner.nextInt();
if(choice == 1) decrypt();
else if(choice == 2) encrypt();
else if(choice == 3) makeKeypair();
}
private static void makeKeypair() throws Exception {
Scanner scanner = new Scanner(System.in);
System.out.println("Enter the name of your public key: ");
publicName = scanner.nextLine() + ".key";
System.out.println("Enter the name of your private key: ");
privateName = scanner.nextLine() + ".key";
KeyMaker keyMaker = new KeyMaker(publicName, privateName);
keyMaker.generateKeys();
}
public static void encrypt() throws Exception {
Scanner scanner = new Scanner(System.in);
System.out.println("Enter the text you want to encrypt: ");
String toEncrypt = scanner.nextLine();
System.out.println("Enter the name of the public key you want to use: ");
publicName = scanner.nextLine() + ".key";
Encrypter encrypter = new Encrypter(publicName);
Key key = generateKey();
String encryptedWithAES = encryptAES(toEncrypt, key);
String encodedKey = java.util.Base64.getEncoder().encodeToString(key.getEncoded());
String encryptedKey = encrypter.rsaEncrypt(encodedKey);
String finalOutput = encryptedKey + encryptedWithAES;
System.out.println("Enter the name of the file encrypted file which will be created: ");
String fileName = scanner.nextLine();
PrintWriter out = new PrintWriter(fileName + ".txt");
out.println(finalOutput);
out.close();
System.out.println("DONE - saved as: " + fileName + ".txt");
scanner.close();
}
public static void decrypt() throws Exception {
Scanner scanner = new Scanner(System.in);
System.out.println("Enter the name of your encrypted file: ");
String fileName = scanner.nextLine() + ".txt";
String givenInput = null;
try (BufferedReader br = new BufferedReader(new FileReader(fileName))) {
String line;
while ((line = br.readLine()) != null) {
givenInput = givenInput + line;
}
}
assert givenInput != null;
String encryptedKey = givenInput.substring(0,172);
String encryptedWithAES = givenInput.replace(encryptedKey, "");
System.out.println("Enter the name of your private key: ");
privateName = scanner.nextLine() + ".key";
Decrypter decrypter = new Decrypter(privateName);
String decryptedKey = decrypter.rsaDecrypt(encryptedKey);
byte[] decodedKey = java.util.Base64.getDecoder().decode(decryptedKey);
Key originalKey = new SecretKeySpec(decodedKey, "AES");
String decryptedWithAES = decryptAES(encryptedWithAES, originalKey);
System.out.println(decryptedWithAES);
scanner.close();
}
public static Key generateKey() throws Exception {
KeyGenerator kg = KeyGenerator.getInstance("AES");
SecureRandom random = new SecureRandom();
kg.init(random);
return kg.generateKey();
}
private static String encryptAES(String message, Key key) throws Exception {
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE,key);
byte[] stringBytes = message.getBytes();
byte[] raw = cipher.doFinal(stringBytes);
return Base64.encodeBase64String(raw);
}
public static String decryptAES(String encrypted, Key key) throws Exception {
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] raw = Base64.decodeBase64(encrypted);
byte[] stringBytes = cipher.doFinal(raw);
return new String(stringBytes, "UTF8");
}
}
KeyMaker.java:
import java.io.FileOutputStream;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
public class KeyMaker {
String publicName;
String privateName;
public KeyMaker(String publicName, String privateName) {
this.publicName = publicName;
this.privateName = privateName;
}
public void generateKeys() throws Exception{
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024);
KeyPair kp = kpg.genKeyPair();
PrivateKey privateKey = kp.getPrivate();
PublicKey publicKey = kp.getPublic();
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(
publicKey.getEncoded());
FileOutputStream fos = new FileOutputStream(publicName);
fos.write(x509EncodedKeySpec.getEncoded());
fos.close();
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(
privateKey.getEncoded());
fos = new FileOutputStream(privateName);
fos.write(pkcs8EncodedKeySpec.getEncoded());
fos.close();
}
}
Encrypter.java:
import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import java.io.*;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
public class Encrypter {
String keyFileName;
public Encrypter(String keyFileName) {
this.keyFileName = keyFileName;
}
public String rsaEncrypt(String data) throws Exception {
PublicKey pubKey = readPublicKeyFromFile(keyFileName);
byte[] utf8 = data.getBytes("UTF-8");
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] enc = cipher.doFinal(Base64.encodeBase64(utf8));
return Base64.encodeBase64String(enc);
}
private PublicKey readPublicKeyFromFile(String keyFileName) throws Exception {
File filePublicKey = new File(keyFileName);
FileInputStream fis = new FileInputStream(keyFileName);
byte[] encodedPublicKey = new byte[(int) filePublicKey.length()];
fis.read(encodedPublicKey);
fis.close();
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(
encodedPublicKey);
PublicKey pubKey = keyFactory.generatePublic(publicKeySpec);
return pubKey;
}
}
Decrypter.java:
import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import java.io.*;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
public class Decrypter {
String keyFileName;
public Decrypter(String keyFileName) {
this.keyFileName = keyFileName;
}
public String rsaDecrypt(String str) throws Exception {
PrivateKey privateKey = readPrivateKeyFromFile(keyFileName);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] dec = Base64.decodeBase64(str);
byte[] utf8 = cipher.doFinal(Base64.decodeBase64(dec));
return Base64.encodeBase64String(utf8);
}
private PrivateKey readPrivateKeyFromFile(String keyFileName) throws Exception {
File filePrivateKey = new File(keyFileName);
FileInputStream fis = new FileInputStream(keyFileName);
byte[] encodedPrivateKey = new byte[(int) filePrivateKey.length()];
fis.read(encodedPrivateKey);
fis.close();
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(
encodedPrivateKey);
PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);
return privateKey;
}
}
In your Decrypter, you decode the Base64-encoded String into bytes, but then you decode that again. In your Encrypter, you take the bytes encrypted, and encode that into Base64 once. This is likely where your problem lies.
Strangely enough, you seem to perform more Base64 operations than necessary. For example, in Encrypter, you get the bytes of the string to encrypt. Why do you Base64-encode those bytes again?
I am trying to do a simple encrypt/decrypt with asymmetric keys in JAVA using RSA keys and i have some troubles. This is my code :
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.RandomAccessFile;
import java.math.BigInteger;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPairGenerator;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.PrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import javax.crypto.Cipher;
public class AsymmetricCipherTestFiles
{
public static void main(String[] unused) throws Exception
{
// 1. Generating keys
System.out.println("Generating keys ...");
PublicKey publicKey;
PrivateKey privateKey;
// generateKeys(512);
// 2. read them from file
System.out.println("Read from file");
publicKey = readPublicKeyFromFile("public.key");
privateKey = readPrivateKeyFromFileTest("private.key");
System.exit(0);
// 3. encrypt data
System.out.println("Encrypt data");
byte[] dataBytes = "some string to encrypt".getBytes();
byte[] encBytes = encrypt(dataBytes, publicKey, "RSA");
printByteArray(encBytes);
// 4. decrypt data
byte[] decBytes = decrypt(encBytes, privateKey, "RSA");
printByteArray(decBytes);
// String decryptedThing = convert(decBytes);
}
public static void generateKeys(int keySize) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException
{
// Create key
// System.out.println("Generating keys");
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(keySize);
KeyPair kp = kpg.genKeyPair();
/*
Key publicKey = kp.getPublic();
Key privateKey = kp.getPrivate();
*/
KeyFactory fact = KeyFactory.getInstance("RSA");
RSAPublicKeySpec pub = fact.getKeySpec(kp.getPublic(),RSAPublicKeySpec.class);
RSAPrivateKeySpec priv = fact.getKeySpec(kp.getPrivate(),RSAPrivateKeySpec.class);
saveKeyToFile("bin/public.key", pub.getModulus(), pub.getPublicExponent());
saveKeyToFile("bin/private.key", priv.getModulus(),priv.getPrivateExponent());
// System.out.println("Keys generated");
}
private static byte[] encrypt(byte[] inpBytes, PublicKey key,String xform) throws Exception
{
Cipher cipher = Cipher.getInstance(xform);
cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(inpBytes);
}
private static byte[] decrypt(byte[] inpBytes, PrivateKey key,String xform) throws Exception
{
Cipher cipher = Cipher.getInstance(xform);
cipher.init(Cipher.DECRYPT_MODE, key);
return cipher.doFinal(inpBytes);
}
public static String convert(byte[] data)
{
StringBuilder sb = new StringBuilder(data.length);
for (int i = 0; i < data.length; ++ i)
{
if (data[i] < 0) throw new IllegalArgumentException();
sb.append((char) data[i]);
}
return sb.toString();
}
public static PublicKey readPublicKeyFromFile(String keyFileName) throws IOException
{
InputStream in = (InputStream) AsymmetricCipherTestFiles.class.getResourceAsStream(keyFileName);
ObjectInputStream oin = new ObjectInputStream(new BufferedInputStream( in ));
try
{
BigInteger m = (BigInteger) oin.readObject();
BigInteger e = (BigInteger) oin.readObject();
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(m, e);
KeyFactory fact = KeyFactory.getInstance("RSA");
PublicKey pubKey = fact.generatePublic(keySpec);
return pubKey;
}
catch (Exception e)
{
throw new RuntimeException("Spurious serialisation error", e);
} finally {
oin.close();
}
}
public static PrivateKey readPrivateKeyFromFile(String keyFileName) throws IOException
{
InputStream in = (InputStream) AsymmetricCipherTestFiles.class.getResourceAsStream(keyFileName);
ObjectInputStream oin = new ObjectInputStream(new BufferedInputStream( in ));
try
{
BigInteger m = (BigInteger) oin.readObject();
BigInteger e = (BigInteger) oin.readObject();
byte[] byteArray = new byte[512];
byteArray = m.toByteArray();
KeySpec keySpec = new PKCS8EncodedKeySpec(byteArray);
// RSAPublicKeySpec keySpec = new RSAPublicKeySpec(m, e);
KeyFactory fact = KeyFactory.getInstance("RSA");
PrivateKey privateKey = fact.generatePrivate(keySpec);
return privateKey;
}
catch (Exception e)
{
throw new RuntimeException("Spurious serialisation error", e);
} finally {
oin.close();
}
}
public static PrivateKey readPrivateKeyFromFileTest(String filename) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException
{
RandomAccessFile raf = new RandomAccessFile(filename, "r");
byte[] buf = new byte[(int)raf.length()];
raf.readFully(buf);
raf.close();
PKCS8EncodedKeySpec kspec = new PKCS8EncodedKeySpec(buf);
KeyFactory kf = KeyFactory.getInstance("RSA");
PrivateKey privKey = kf.generatePrivate(kspec);
return privKey;
}
public static void saveKeyToFile(String fileName,BigInteger mod, BigInteger exp) throws IOException
{
ObjectOutputStream oout = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(fileName)));
try
{
oout.writeObject(mod);
oout.writeObject(exp);
}
catch (Exception e)
{
throw new IOException("Unexpected error", e);
}
finally
{
oout.close();
}
}
public static void printByteArray(byte[] byteArray)
{
int increment = 0;
for(byte b : byteArray)
{
System.out.println("B["+increment+"] = "+b);
increment++;
}
}
}
When i run it it gives me this error :
Generating keys ...
Read from file
Exception in thread "main" java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException : DerInputStream.getLength(): lengthTag=109, too big.
at sun.security.rsa.RSAKeyFactory.engineGeneratePrivate(Unknown Source)
at java.security.KeyFactory.generatePrivate(Unknown Source)
at AsymmetricCipherTestFiles.readPrivateKeyFromFileTest(AsymmetricCipherTestFiles.java:160)
at AsymmetricCipherTestFiles.main(AsymmetricCipherTestFiles.java:40)
Caused by: java.security.InvalidKeyException: IOException : DerInputStream.getLength(): lengthTag=109, too big.
at sun.security.pkcs.PKCS8Key.decode(Unknown Source)
at sun.security.pkcs.PKCS8Key.decode(Unknown Source)
at sun.security.rsa.RSAPrivateCrtKeyImpl.<init>(Unknown Source)
at sun.security.rsa.RSAPrivateCrtKeyImpl.newKey(Unknown Source)
at sun.security.rsa.RSAKeyFactory.generatePrivate(Unknown Source)
... 4 more
The thing is that at generating/reading/encrypting with public key everything works smoothly, the error occurs when reading private key and trying to get it into an PrivateKey object.
What i am doing wrong and how i may solve this?
Thanks.
You're saving the key with two writeObject() calls but retreiving it with a single readFully() call. You need to either:
save the key with write(byte[]), supplying the result of getEncoded(), and read it with readFully(), or
save it with writeObject() and read it with readObject().
Not a mixture of the two.
I am working on a concept of encryption and decryption using ecc.
I already generated public and private key. While I am encrypting the text I am getting this error:
java.security.InvalidKeyException: ECKeyAgreement requires ECPrivateKey
at
org.bouncycastle.jce.provider.JCEECDHKeyAgreement.engineInit(JCEECDHKeyAgreement.java:121)
at javax.crypto.KeyAgreement.init(KeyAgreement.java:462)
at javax.crypto.KeyAgreement.init(KeyAgreement.java:436)
at rbl2015.encryec.main(encryec.java:67)
This is my encryption Java file:
import java.io.File;
import java.io.FileInputStream;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.spec.ECParameterSpec;
import java.security.spec.EllipticCurve;
import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Scanner;
import javax.crypto.Cipher;
import javax.crypto.KeyAgreement;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public class encryec
{
KeyPairGenerator kpg;
EllipticCurve curve;
ECParameterSpec ecSpec;
KeyPair aKeyPair;
static KeyAgreement aKeyAgree;
KeyPair bKeyPair;
KeyAgreement bKeyAgree;
KeyFactory keyFac;
static String msg;
public static void main(String args[])
{
Security.addProvider(new BouncyCastleProvider());
Scanner ss=new Scanner(System.in);
try{
String path = "D:\\rp";
File filePublicKey = new File(path+"\\public.key");
FileInputStream fis = new FileInputStream(path+"\\public.key");
byte[] encodedPublicKey = new byte[(int) filePublicKey.length()];
fis.read(encodedPublicKey);
fis.close();
// Read Private Key.
File filePrivateKey = new File(path+"\\private.key");
fis = new FileInputStream(path+"\\private.key");
byte[] encodedPrivateKey = new byte[(int) filePrivateKey.length()];
fis.read(encodedPrivateKey);
fis.close();
KeyFactory keyFactory = KeyFactory.getInstance("ECDH");
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(
encodedPublicKey);
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(encodedPrivateKey);
PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);
aKeyAgree = KeyAgreement.getInstance("ECDH", "BC");
aKeyAgree.init(privateKey); // exception line
aKeyAgree.doPhase(publicKey, true);
byte[] aBys = aKeyAgree.generateSecret();
KeySpec aKeySpec = new DESKeySpec(aBys);
SecretKeyFactory aFactory = SecretKeyFactory.getInstance("DES");
Key aSecretKey = aFactory.generateSecret(aKeySpec);
Cipher aCipher = Cipher.getInstance(aSecretKey.getAlgorithm());
aCipher.init(Cipher.ENCRYPT_MODE, aSecretKey);
byte[] encText = aCipher.doFinal("Its Rahul".getBytes());
System.out.println(Base64.encodeBase64String(encText));
System.out.println(encText);
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
I don't know what I am missing. I tried everything that I can to get the ECPrivateKey.
This is the code for generating the public and private key:
import java.io.*;
import java.security.*;
import java.security.spec.*;
public class Rahul {
public static void main(String args[]) {
Rahul rahul = new Rahul();
try {
String path = "D:\\rp";
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA");
keyGen.initialize(1024);
KeyPair generatedKeyPair = keyGen.genKeyPair();
System.out.println("Generated Key Pair");
rahul.dumpKeyPair(generatedKeyPair);
rahul.SaveKeyPair(path, generatedKeyPair);
KeyPair loadedKeyPair = rahul.LoadKeyPair(path, "DSA");
System.out.println("Loaded Key Pair");
rahul.dumpKeyPair(loadedKeyPair);
} catch (Exception e) {
e.printStackTrace();
return;
}
}
private void dumpKeyPair(KeyPair keyPair) {
PublicKey pub = keyPair.getPublic();
System.out.println("Public Key: " + getHexString(pub.getEncoded()));
PrivateKey priv = keyPair.getPrivate();
System.out.println("Private Key: " + getHexString(priv.getEncoded()));
}
private String getHexString(byte[] b) {
String result = "";
for (int i = 0; i < b.length; i++) {
result += Integer.toString((b[i] & 0xff) + 0x100, 16).substring(1);
}
return result;
}
public void SaveKeyPair(String path, KeyPair keyPair) throws IOException {
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();
// Store Public Key.
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(
publicKey.getEncoded());
FileOutputStream fos = new FileOutputStream(path + "/public.key");
fos.write(x509EncodedKeySpec.getEncoded());
fos.close();
// Store Private Key.
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(
privateKey.getEncoded());
fos = new FileOutputStream(path + "/private.key");
fos.write(pkcs8EncodedKeySpec.getEncoded());
fos.close();
}
public KeyPair LoadKeyPair(String path, String algorithm)
throws IOException, NoSuchAlgorithmException,
InvalidKeySpecException {
// Read Public Key.
File filePublicKey = new File(path + "/public.key");
FileInputStream fis = new FileInputStream(path + "/public.key");
byte[] encodedPublicKey = new byte[(int) filePublicKey.length()];
fis.read(encodedPublicKey);
fis.close();
// Read Private Key.
File filePrivateKey = new File(path + "/private.key");
fis = new FileInputStream(path + "/private.key");
byte[] encodedPrivateKey = new byte[(int) filePrivateKey.length()];
fis.read(encodedPrivateKey);
fis.close();
// Generate KeyPair.
KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(
encodedPublicKey);
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(
encodedPrivateKey);
PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);
return new KeyPair(publicKey, privateKey);
}
}
You should try and create an EC(DH) key pair instead of a DSA key pair. Although the general method of operation is identical (both ECDSA and DSA are based on the Diffie-Hellman problem) the key types are certainly not.