RSA 512 bit implementation in android with NO PADDING - java

My question is that on how to use RSA 512 bit in Android; I was able to generate the public and private keys by looking up on the internet but not sure if its with NO padding as I could not find any solution for it.The public key would be sent to the server also with the integer encrypted with the private key.
I am new to it so it would be great to have some help. Thanks!
genreateKeys("RSA",512)
The following code:
private static void generateKeys(String keyAlgorithm, int numBits) {
try {
// Get the public/private key pair
KeyPairGenerator keyGen = KeyPairGenerator.getInstance(keyAlgorithm);
keyGen.initialize(numBits);
KeyPair keyPair = keyGen.genKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();
System.out.println("\n" + "Generating key/value pair using " + privateKey.getAlgorithm() + " algorithm");
// Get the bytes of the public and private keys
byte[] privateKeyBytes = privateKey.getEncoded();
byte[] publicKeyBytes = publicKey.getEncoded();
// Get the formats of the encoded bytes
String formatPrivate = privateKey.getFormat(); // PKCS#8
String formatPublic = publicKey.getFormat(); // X.509
System.out.println("Private Key : " + HttpRequest.Base64.encode(String.valueOf(privateKeyBytes)));
System.out.println("Public Key : " + HttpRequest.Base64.encode(String.valueOf(publicKeyBytes)));
// The bytes can be converted back to public and private key objects
KeyFactory keyFactory = KeyFactory.getInstance(keyAlgorithm);
EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
PrivateKey privateKey2 = keyFactory.generatePrivate(privateKeySpec);
EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeyBytes);
PublicKey publicKey2 = keyFactory.generatePublic(publicKeySpec);
// The original and new keys are the same
System.out.println(" Are both private keys equal? " + privateKey.equals(privateKey2));
System.out.println(" Are both public keys equal? " + publicKey.equals(publicKey2));
} catch (InvalidKeySpecException specException) {
System.out.println("Exception");
System.out.println("Invalid Key Spec Exception");
} catch (NoSuchAlgorithmException e) {
System.out.println("Exception");
System.out.println("No such algorithm: " + keyAlgorithm);
}
}
It gives me the output of public and private keys but its not with NO PADDING also how can I use the private key to encrypt my integer value?

Related

decryption error occurring when using rsa in java.

My aim is to take in a message containing a challenge and an origin. On receiving this msg a rsa keypair must be generated which is then used to manipulate the data as shown below. Certain part of the data is encrypted using the generated public key. During authorization, that data must be decrypted with the private key. However, when i try to decrypt it is shows a decryption error. I have even printed different parts of the code just to check if the desired output is achieved which is why i know the private key taken from file is correct. I am unable to solve the decryption error. The specifications for the task require the use of rsa and not hybrid encryption. i have tried padding but that didnt help. please advice on how to solve this problem
package pam;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.xml.bind.DatatypeConverter;
import com.sun.jersey.core.util.Base64;
class Test
{
public static void kpgen(int numBits, String s) throws Exception
{
if(s.length()!=64)
{
System.out.println("invalid entry");
}
else
{
KeyPairGenerator keygen = KeyPairGenerator.getInstance("RSA");
KeyPair keyPair = keygen.genKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();
System.out.println("pk: "+privateKey);
System.out.println("pubk: "+publicKey);
String fileBase = "f:\\tempKey"; //WRITING PVT KEY TO FILE
try (FileOutputStream out = new FileOutputStream(fileBase + ".key"))
{
out.write(keyPair.getPrivate().getEncoded());
}
try (FileOutputStream out = new FileOutputStream(fileBase + ".pub"))
{
out.write(keyPair.getPublic().getEncoded());
}
System.out.println("Key pair : " + Base64.encode(String.valueOf(keyPair)));
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] digest = md.digest(keyPair.toString().getBytes(StandardCharsets.UTF_8));
String sha256 = DatatypeConverter.printHexBinary(digest).toLowerCase();
System.out.println("Hash value: "+sha256);
String ch = s.substring(0,32);
String or = s.substring(32,64);
System.out.println("Challenge: "+ch);
System.out.println("Origin: "+or);
MessageDigest md1 = MessageDigest.getInstance("SHA-256");
byte[] digest1 = md1.digest(privateKey.toString().getBytes(StandardCharsets.UTF_8));
String sha = DatatypeConverter.printHexBinary(digest1).toLowerCase();
or = or + sha;
System.out.println("String kh: "+or);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] keyHandle = cipher.doFinal(or.getBytes());
System.out.println("Key Handle: "+keyHandle);
String f = "f:\\keyList.pub";
Key pub = getKeyFromFile(f);
System.out.println("Attestation Public Key: "+pub);
PrivateKey pk = (PrivateKey) getPvtKey("f:\\keyList.key");
Signature rsa = Signature.getInstance("SHA1withRSA");
rsa.initSign(pk);
rsa.update(ch.getBytes());
byte[] sc = rsa.sign();
System.out.println("Signed challenge: "+sc);
String rm = publicKey.toString() + pub + sc + keyHandle;
System.out.println("Response Msg: " +rm);
}
}
public static Key getKeyFromFile(String fileName) throws Exception
{
byte[] bytes = Files.readAllBytes(Paths.get(fileName));
X509EncodedKeySpec ks = new X509EncodedKeySpec(bytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
PublicKey pub = kf.generatePublic(ks);
return pub;
}
public static PrivateKey getPvtKey(String s) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException
{
byte[] bytes = Files.readAllBytes(Paths.get(s));
PKCS8EncodedKeySpec ks = new PKCS8EncodedKeySpec(bytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
PrivateKey pvt = kf.generatePrivate(ks);
return pvt;
}
public static void auth(String s) throws NoSuchAlgorithmException, Exception, IOException
{
String chal = s.substring(0, 32);
String origin = s.substring(32,64);
String kh = s.substring(64);
byte[] kh1 = kh.getBytes();
PrivateKey pvtKey = getPvtKey("f:\\tempKey.key"); //READING THE PRIVATE KEY MADE IN KPGEN
System.out.println("pk: "+pvtKey);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, pvtKey);
byte[] keyHandle = cipher.doFinal(kh1);
String or = keyHandle.toString().substring(0, (kh.length()/2));
String pk = keyHandle.toString().substring(kh.length()/2);
int c = 0;
if(or.equals(origin))
{
c++;
}
else
{
System.out.println("Bad Key Handle: Invalid Origin");
}
if(pk.equals(pvtKey.toString()))
{
c++;
}
else
{
System.out.println("Bad Key Handle: invalid private key");
}
if(c==2)
{
Signature rsa = Signature.getInstance("SHA1withRSA");
rsa.initSign((PrivateKey) pvtKey);
rsa.update(chal.getBytes());
byte[] sc = rsa.sign();
System.out.println("Signed Challenge: "+sc);
}
else
System.out.println("error");
}
}
You have multiple (many) issues in your code with the encryption
First - encode properly your data, String in Java is to represent printable characters. As soon as you work with encryption (working on byte[] level), you need to encode or decode the values.
Example - your code will print the "keyHandle", it's a byte array object hash, not really the encrypted data itself
byte[] keyHandle = cipher.doFinal(or.getBytes());
System.out.println("Key Handle: "+keyHandle);
...
String rm = publicKey.toString() + pub + sc + keyHandle;
Use at hex or base64 encoding to print out the output. The same applies to the signature.
I am unable to solve the decryption error.
String kh = s.substring(64);
byte[] kh1 = kh.getBytes();
..
byte[] keyHandle = cipher.doFinal(kh1);
And you simply assume you can decrypt some random substring? Encrypting using RSA will produce output of size of the key (e.g. 2048 bits) and you have to store and decrypt as whole, not any substring.
As a learning exercise - try to simply encrypt and decrypt, encode, decode to learn the primitives you can (re)use.

Convert a PGP Public Key

Does anybody know if there is a way to convert a public key with the pgp public key format to the X.509 key format? Maybe using Bouncy Castle or something familiar?
Because right now I am able to decode a X.509 public key using X509EncodedKeySpecs and PublicKey, but this doesn't work with the PGP key format.
byte[] decodeValue = Base64.decode(schluesselstring.getBytes(), Base64.DEFAULT);
X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(decodeValue);
try {
KeyFactory keyFact = KeyFactory.getInstance("RSA");
try {
PublicKey publicKey = keyFact.generatePublic(pubKeySpec);
schluessel = "schluessel";
Log.d("TEST", "publicKey = " + publicKey.toString());
Log.d("TEST", "Algorithm = " + publicKey.getAlgorithm());
Log.d("TEST", "Format = " + publicKey.getFormat());
}
catch...
}
When I try to use this code on a PGP key I get an error message because it's not ANSC.1 . I also tried to use different KeySpecs but none worked.
The standard that "X.509" (SPKI) and "PKCS8" keys, and other things like certificates, use is Abstract Syntax Notation One ASN.1. Standard Java crypto doesn't handle PGP but yes BouncyCastle (bcpg) can do this just fine (updated 2021-02: JcaPGPKeyConverter does the whole job, and for all algorithms):
static void SO40831894PGPPubkeyCvtBC (String[] args) throws Exception {
// adapted from org.bouncycastle.openpgp.examples.PubringDump
try (InputStream in = new FileInputStream (args[0])){
PGPPublicKeyRingCollection pubRings = new PGPPublicKeyRingCollection(
PGPUtil.getDecoderStream(in), new JcaKeyFingerprintCalculator());
Iterator<PGPPublicKeyRing> rIt = pubRings.getKeyRings();
while (rIt.hasNext()){
PGPPublicKeyRing pgpPub = (PGPPublicKeyRing)rIt.next();
Iterator<PGPPublicKey> it = pgpPub.getPublicKeys();
while (it.hasNext()){
PGPPublicKey pgpKey = (PGPPublicKey)it.next();
System.out.println(pgpKey.getClass().getName()
+ " KeyID: " + Long.toHexString(pgpKey.getKeyID())
+ " type: " + pgpKey.getAlgorithm()
+ " fingerprint: " + new String(Hex.encode(pgpKey.getFingerprint())));
/* don't need to do this >>>
BCPGKey bcKey = pgpKey.getPublicKeyPacket().getKey();
//System.out.println (bcKey.getClass().getName());
if( bcKey instanceof RSAPublicBCPGKey ){
RSAPublicBCPGKey bcRSA = (RSAPublicBCPGKey)bcKey;
RSAPublicKeySpec specRSA = new RSAPublicKeySpec( bcRSA.getModulus(), bcRSA.getPublicExponent());
PublicKey jceKey = KeyFactory.getInstance("RSA").generatePublic(specRSA);
<<< instead just: */
{
PublicKey jceKey = new JcaPGPKeyConverter().getPublicKey(pgpKey);
// if you want to use the key in JCE, jceKey is now ready
// if you want to write "X.509" (SPKI) DER format to a file:
Files.write(new File(args[1]).toPath(), jceKey.getEncoded());
// if you want to write in PEM, bouncycastle can do that too
return;
}
}
}
}
}

Encrypt and decrypt a SecretKey with RSA public and private keys

I am trying to encrypt a secretKey with my publicKey, then decrypt it somewhere else with the private key. I can encrypt and decrypt fine, However I am getting a completely different key back when I do this.
Here is the code that creates the public/ private keypair
public static KeyPair generateKeyPair()
{
KeyPair returnPair = null;
try
{
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", "SunJSSE");
System.out.println("provider:" + kpg.getProvider().getName());
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
kpg.initialize(1024, random);
returnPair = kpg.generateKeyPair();
}catch(Exception e)
{
e.printStackTrace();
}
return returnPair;
}
I specified the SunJSSE provider, although I am not getting any different result than when I ran with DiffieHellman from SunJCE or the RSA/ SunRSASign provider. I am new to java security so these concepts are still a little above my head.
Here is the code I use to generate the secret key
public static SecretKey generateSecretKey(String keyPassword)
{
SecretKey key = null;
try
{
SecretKeyFactory method = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
//System.out.println("salt length: " + new SaltIVManager().getSalt().length);
PBEKeySpec spec = new PBEKeySpec(keyPassword.toCharArray(), new SaltIVManager().getSalt(), 10000, 128);
key = method.generateSecret(spec);
System.out.println("generate secret key length: " + key.getEncoded().length);
}catch(Exception e)
{
e.printStackTrace();
}
return key;
}
And here are the two methods I use to encrypt/ decrypt my secret key
public static byte[] encryptSecretKey(SecretKey secretKey, PublicKey publicKey)
{
byte[] encryptedSecret = null;
try
{
Cipher cipher = Cipher.getInstance("RSA/ECB/NOPADDING");
System.out.println("provider: " + cipher.getProvider().getName());
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
System.out.println("original secret key: " + Base64.getEncoder().encodeToString(secretKey.getEncoded()) + " \n secretkey encoded length: " + secretKey.getEncoded().length);
encryptedSecret = cipher.doFinal(secretKey.getEncoded());
System.out.println("encrypted secret: " + Base64.getEncoder().encodeToString(encryptedSecret));
}catch(Exception e)
{
e.printStackTrace();
}
return encryptedSecret;
}
public static SecretKey decryptSecretKey(byte[] encryptedKey, PrivateKey privateKey)
{
SecretKey returnKey = null;
try
{
Cipher cipher = Cipher.getInstance("RSA/ECB/NOPADDING");
System.out.println("provider: " + cipher.getProvider().getName());
cipher.init(Cipher.DECRYPT_MODE, privateKey);
System.out.println("encryptedkey length: " + encryptedKey.length);
byte [] encodedSecret = cipher.doFinal(encryptedKey);
System.out.println("encoded Secret after decrypt: " + Base64.getEncoder().encodeToString(encodedSecret));
returnKey = new SecretKeySpec(encodedSecret, 0, encodedSecret.length, "PBEWithMD5AndDES");
System.out.println("secret key: " + Base64.getEncoder().encodeToString(returnKey.getEncoded()));
System.out.println("secret key length post decrypt: " + returnKey.getEncoded().length);
}catch(Exception e)
{
e.printStackTrace();
}
return returnKey;
}
The RSA algorithm is the only one I have gotten to work with my keys. If I specify the DiffieHellman alg. for the keypair, I am unable to encrypt/ decrypt at all. If anyone has any insight into what I have done wrong, any help would be greatly appreciated. When I call this in its current state, I start with a secretkey of this value = cGFzczEyMw== and end with a key of this value after encryption/ decryption
SvMNufKu2JA4hnNEwuWdOgJu6FxnNmuLYzxENhTsGgFzc/i3kQIXbeVaJUkJck918BLCnm2u2QZCyVvJjYFXMLBFga0Zq0WMxSbIZvPz1J/EDi9dpsAkbFhLyBWmdDyPr+w7DMDsqHwKuA8y/IRKVINWXVrp3Hbt8goFZ0nGIlKVzMdJbGhNi3HZSAw4R6fXZNKOJ3nN6wDldzYerEaz2MhJqnZ3Dz4psA6gskomhjp/G0yhsGO8pllMcgD0jzhL86RGrBhjj04Bj0ps3AAACkQLcCwisso8dWigvR8NX9dnI0C/gc6FqmNenWI1/AoPgmcRyFdlO7A2i9JXoSj+YQ==
You first should know what you are trying to do before doing it:
RSA without padding is completely insecure;
you use a key for Password Based Encryption which only makes sense with - well - a password;
you come out with a DES key, which again is completely insecure;
you probably generate it with a salt, which is random, so the output is random.
The whole protocol doesn't make sense. That you're trying to encrypt directly with DH (a scheme to perform key agreement) shows that you haven't studied crypto enough.
With cryptography it's not about getting things to work. It's about getting things secure. You cannot do that by just trying things out. Learn at least the basics of cryptography then code.
The issue in fact was the way in which I was storing/ retrieving my keys. I had used a keystore for the private and a file for the public. The way in which I retrieved these keys was causing them to become malformed, thus the failure in my cipher and the need to run with NOPADDING in order to get any sort of output.
Here is the new storage code I am using for RSA keys- writing them to a file.
public static boolean saveKeys(Key privateKey, Key publicKey, char[] password, String alias)
{
boolean saved = false;
try
{
KeyPair kp = generateKeyPair();
KeyFactory kf = KeyFactory.getInstance("RSA");
if(privateKey != null)
{
File privKeyFile = new File(System.getProperty("user.home") + "/.etc/privkey");
if(!privKeyFile.exists())
{
privKeyFile.createNewFile();
}
System.out.println("private key: " + Base64.getEncoder().encodeToString(kp.getPrivate().getEncoded()));
RSAPrivateKeySpec pubSpec = kf.getKeySpec(kp.getPrivate(), RSAPrivateKeySpec.class);
ObjectOutputStream oout = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(System.getProperty("user.home") + "/.etc/privkey")));
oout.writeObject(pubSpec.getModulus());
oout.writeObject(pubSpec.getPrivateExponent());
oout.close();
}if(publicKey != null)
{
File pubKeyFile = new File(System.getProperty("user.home") + "/.etc/pubkey.pub");
if(!pubKeyFile.exists())
{
pubKeyFile.createNewFile();
}
System.out.println("public key: " + Base64.getEncoder().encodeToString(kp.getPublic().getEncoded()));
RSAPublicKeySpec pubSpec = kf.getKeySpec(kp.getPublic(), RSAPublicKeySpec.class);
ObjectOutputStream oout = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(System.getProperty("user.home") + "/.etc/pubkey.pub")));
oout.writeObject(pubSpec.getModulus());
oout.writeObject(pubSpec.getPublicExponent());
oout.close();
}
}catch(Exception e)
{
e.printStackTrace();
}
return saved;
}

Generating ECDSA public key at host side from W parameter

I want to send the public key of the private-public key pair (ECDSA) generated in my applet to the host application/terminal.
In RSA normally i would send the modulus and exponent and will generate the public key at the host side.
In ECDSA i read from the link that we can do the same if you take the W parameter bytes outside the card Click here: Stackoverflow Answer: encode public key on Java
I have the W bytes from the card now. can someone suggest how to create the public key from this?
I wrote this method to convert an EC Public key into java.security.interfaces.ECPublicKey key object. To do this I use Bouncy Castle provider (bcprov-ext-jdk16-1.46.jar). You can download the latest version from here.
/**
* This method converts the EC public key (ECPublicKey#getW()) into ECPublicKey
* #param cardPublicKey as W
* #param curveName (for example "P-224")
* #return java.security.interfaces.ECPublicKey
*/
public ECPublicKey ucPublicKeyToPublicKey(byte[] cardPublicKey, String curveName) {
//for example curveName = "P-224";
java.security.interfaces.ECPublicKey ecPublicKey = null; // java.security.interfaces.ECPublicKey
java.security.KeyFactory kf = null;
org.bouncycastle.jce.spec.ECNamedCurveParameterSpec ecNamedCurveParameterSpec = ECNamedCurveTable.getParameterSpec(curveName);
org.bouncycastle.math.ec.ECCurve curve = ecNamedCurveParameterSpec.getCurve();
java.security.spec.EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, ecNamedCurveParameterSpec.getSeed());
java.security.spec.ECPoint ecPoint = ECPointUtil.decodePoint(ellipticCurve, cardPublicKey);
java.security.spec.ECParameterSpec ecParameterSpec = EC5Util.convertSpec(ellipticCurve, ecNamedCurveParameterSpec);
java.security.spec.ECPublicKeySpec publicKeySpec = new java.security.spec.ECPublicKeySpec(ecPoint, ecParameterSpec);
try {
kf = java.security.KeyFactory.getInstance("EC", "BC");
} catch (Exception e) {
System.out.println("Caught Exception kf : " + e.toString());
}
try {
ecPublicKey = (ECPublicKey) kf.generatePublic(publicKeySpec);
} catch (Exception e) {
System.out.println("Caught Exception public key: " + e.toString());
}
return ecPublicKey;
}

RSA Encrypted chiper text to string and decrypting throwing javax.crypto.IllegalBlockSizeException: Data must not be longer than 117 bytes

private static String decrypt(String cipherString, PrivateKey key) {
byte[] dectyptedText = null;
byte[] stringText = null;
try {
// get an RSA cipher object and print the provider
final Cipher cipher = Cipher.getInstance(ALGORITHM);
//chiper init in encrypt mode
cipher.init(Cipher.ENCRYPT_MODE, key);
//tried to get bytes out of encrypted string
stringText = cipher.doFinal(cipherString.getBytes());
// decrypt the text using the private key
cipher.init(Cipher.DECRYPT_MODE, key);
dectyptedText = cipher.doFinal(stringText);
} catch (Exception ex) {
ex.printStackTrace();
}
return new String(dectyptedText);
}
I want to convert the cipher text into bytes generated by the encryptor to a string and store in a database. Then get the string and decrypt it whenever its needed. Is there anyone that could help me solving the issue I'm having?
I does not make sense to convert the byte-Array to String.
You have to either save the bytes directly (which would require an appropriate column in the database, for example BLOB), or you could encode the byte-Array, for example using Base64 (I would recommend the latter).
(If your problems are with the "public-crypto thingy", you may want to use the public key to encrypt, but the private key to decrypt. If you dont know what that means, check out some literature about public-key crypto, please.)
Since your problem seems to be with your key, you possibly need a public key and a private key, not only a private key.
Have a look at this simple RSA demo:
encryptionAlgorithm = "RSA/ECB/PKCS1Padding";
algorithm = "RSA";
try {
SecureRandom random = SecRandom.getDefault();
// Since you are working with asymmetric crypto, you need a keypair:
KeyPairGenerator kpg = KeyPairGenerator.getInstance(algorithm);
kpg.initialize(2048, random);
KeyPair kp = kpg.generateKeyPair();
// encrypting something with asymmetric crypto needs a public key:
Cipher cipher1 = Cipher.getInstance(encryptionAlgorithm);
cipher1.init(Cipher.ENCRYPT_MODE, kp.getPublic());
byte[] text = "This is a test".getBytes("ASCII");
System.out.println("text = " +(new String(text)));
byte[] ciphertext = cipher1.doFinal(text);
// here you could store & load your sipertext
System.out.println("ciphertext = " + ciphertext);
// decrypting something with asymmetric crypto needs a private key:
Cipher cipher2 = Cipher.getInstance(encryptionAlgorithm);
cipher2.init(Cipher.DECRYPT_MODE, kp.getPrivate());
byte[] cleartext = cipher2.doFinal(ciphertext);
System.out.println("cleartext = " +(new String(cleartext)));
} catch (Exception e) {
e.printStackTrace();
}

Categories

Resources