I'm trying to encrypt data using a given public key.
public static final String public_key = "MIIBCgKCAQEAr/oYAoxIcXnLzVDNN6TPJVjkwOJZnDcSEeoRntqhOvgjiycfswMWZZ5+UClJ4CMgMCVAs71BzAJzPv902Jt763SPkAO/vh6CwfLq2S3YcqDoRQJYZuSKQHW40R6sN7eFvQdxYhJnF45ketCdLdPFuF5o/ieChwLcCEDKzkWD7xio2TQlZ8jfzB4jNGr6bmW/aqF5ihe0pbhtfvlyM+jNF2vWeB1SCJ4v5zHLNKKYNy4cMsmIGHKB+0BaGVz87eYp65FFc2K9LawBBbWtVCxykYBzEnXRuU+0YzcTi4LThXg1cUsf++LK9qL/G7PZdN6HMGP7DYzgstFLfp8VRpKhqQIDAQAB";
String encryptData(String txt)
{
String encoded = null;
try {
PublicKey key = KeyFactory.getInstance("RSA").generatePublic(
new X509EncodedKeySpec(Base64.decode(public_key, Base64.DEFAULT)));
Cipher cph = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cph.init(Cipher.ENCRYPT_MODE, key);
encoded = Base64.encodeToString(cph.doFinal(txt.getBytes()),
Base64.DEFAULT);
}
catch (Exception e) {
e.printStackTrace();
}
return encoded;
}
And get the error
W/System.err: java.security.spec.InvalidKeySpecException:
java.lang.RuntimeException: error:0D0680A8:asn1 encoding routines:ASN1_CHECK_TLEN:wrong tag
at com.android.org.conscrypt.OpenSSLKey.getPublicKey(OpenSSLKey.java:143)
at com.android.org.conscrypt.OpenSSLRSAKeyFactory.engineGeneratePublic(OpenSSLRSAKeyFactory.java:47)
at java.security.KeyFactory.generatePublic(KeyFactory.java:172)
I have used the same public key in Python3, with the 'BEGIN PUBLIC KEY...END PUBLIC KEY' header/footer and it works fine:
public_key = """-----BEGIN PUBLIC KEY-----
MIIBCgKCAQEAr/oYAoxIcXnLzVDNN6TPJVjkwOJZnDcSEeoRntqhOvgjiycfswMWZZ5+UClJ4CMgMCVAs71BzAJzPv902Jt763SPkAO/vh6CwfLq2S3YcqDoRQJYZuSKQHW40R6sN7eFvQdxYhJnF45ketCdLdPFuF5o/ieChwLcCEDKzkWD7xio2TQlZ8jfzB4jNGr6bmW/aqF5ihe0pbhtfvlyM+jNF2vWeB1SCJ4v5zHLNKKYNy4cMsmIGHKB+0BaGVz87eYp65FFc2K9LawBBbWtVCxykYBzEnXRuU+0YzcTi4LThXg1cUsf++LK9qL/G7PZdN6HMGP7DYzgstFLfp8VRpKhqQIDAQAB
-----END PUBLIC KEY-----
"""
def encode(msg):
rsa_key = RSA.importKey(public_key)
pks1_v1_5 = PKCS1_v1_5.new(rsa_key)
encrypted = pks1_v1_5.encrypt(msg.encode('utf-8'))
encrypted = base64.b64encode(encrypted)
return encrypted
Can someone help me out plz?
--- EDIT ---
I did some debugging on the Python code: stepping into 'RSA.importKey(public_key)' I see it recognizes the key as PEM encoded key, removes the header/footer and converts it to binary (binascii.a2b_base64). The binary is passed to RSA._importKeyDER which discovers that it follows the PKCS#1 standard and, in comment, 'The DER object is an RSAPublicKey SEQUENCE with two elements'.
Are you generate your public key from openssl, since your public key is too long:
for example i generated from openssl and replace your public key, and everything fine:
openssl genrsa -out key.pem 1024
openssl rsa -in key.pem -pubout > key.pub
and paste key.pub string in your code.
Related
I am using SafetyNet to verify the integrity of the android app.
This is the flow as of now.
I generate a nonce value in the server and send it to the SafetyNet service to get the response.
I get the response from the server. Now I want to verify the result on the server.
I get a base64 string. I decode it and get the response as below.
{
"evaluationType": "BASIC",
"ctsProfileMatch": false,
"apkPackageName": "com.test.safetynetproject",
"apkDigestSha256": "CbU9JzwRzQneYqnEXewB56ZzPm1DgQ4LGUK0eGlWmyM=",
"nonce": "U2FnYXI=",
"apkCertificateDigestSha256": [
"AJRBzWCfJIY7QD2cp4sv9t0cCGMRGdxuID9VdPLV1H4="
],
"timestampMs": 1624099377557,
"basicIntegrity": false
}
Now i want to verify the apkCertificateDigestSha256. The sha256 created from my system using cmd is -
C:\Program Files\Java\jdk-11.0.11\bin>keytool -list -v -alias androiddebugkey -keystore C:\Users\.android\debug.keystore
Enter keystore password:
Alias name: androiddebugkey
Creation date: May 25, 2021
Entry type: PrivateKeyEntry
Certificate chain length: 1
Certificate[1]:
Owner: C=US, O=Android, CN=Android Debug
Issuer: C=US, O=Android, CN=Android Debug
Serial number: 1
Valid from: Tue May 25 11:48:00 IST 2021 until: Thu May 18 11:48:00 IST 2051
Certificate fingerprints:
SHA1: 43:16:E2:63:DB:2A:53:7C:7D:BB:E9:80:7B:05:1C:74:7C:84:66:A2
SHA256: 00:94:41:CD:60:9F:24:86:3B:40:3D:9C:A7:8B:2F:F6:DD:1C:08:63:11:19:DC:6E:20:3F:55:74:F2:D5:D4:7E
Signature algorithm name: SHA1withRSA (weak)
Subject Public Key Algorithm: 2048-bit RSA key
Version: 1
Warning:
The certificate uses the SHA1withRSA signature algorithm which is considered a security risk. This algorithm will be disabled in a future update.
The SHA256
00:94:41:CD:60:9F:24:86:3B:40:3D:9C:A7:8B:2F:F6:DD:1C:08:63:11:19:DC:6E:20:3F:55:74:F2:D5:D4:7E
Question -
I want to verify if the apkCertificateDigestSha256 is the same as the app certificate. Bt unable to find any way to do it.
Tries-
I tried to base64 decode the AJRBzWCfJIY7QD2cp4sv9t0cCGMRGdxuID9VdPLV1H4= and got a random byte array that does not match with the sha256 created in cmd.
Code -
val decode =
String(
Base64.decode(
responseJws!!.apkCertificateDigestSha256!![0],
Base64.DEFAULT
),
StandardCharsets.UTF_8
)
The output -
���A�`�$�;#=���/��c�n ?Ut���~
This is not matching 43:16:E2:63:DB:2A:53:7C:7D:BB:E9:80:7B:05:1C:74:7C:84:66:A2.
Update-
Found some ref but dont really know how to achieve this.
Ref1
How do I do the matching?
I have used SafetyNet API for accessing device's runtime env. I have kept signing certificate of app on server to verify its sha256 against what we get in the SafetyNet response. Below are the steps you can refer if applies to you too.
Get SHA256 fingerprint of signing X509Certificate
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] der = cert.getEncoded();
md.update(der);
byte[] sha256 = md.digest();
Encode sha256 to base64 string
String checksum = Base64.getEncoder().encodeToString(sha256)
Match checksum with apkCertificateDigestSha256 of SafetyNet response
I think this can help you
1.Find AttestationStatement file in GG example. and add this function:
public String bytesToHex(byte[] bytes) {
StringBuffer result = new StringBuffer();
for (byte b : bytes) result.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1));
return result.toString();
}
2.Find getApkCertificateDigestSha256 function and edit like this:
public byte[][] getApkCertificateDigestSha256() {
byte[][] certs = new byte[apkCertificateDigestSha256.length][];
for (int i = 0; i < apkCertificateDigestSha256.length; i++) {
certs[i] = Base64.decodeBase64(apkCertificateDigestSha256[i]);
System.out.println(bytesToHex(certs[i]));
}
return certs;
}
3.Find process() function in OnlineVerrify and add like this:
if (stmt.getApkPackageName() != null && stmt.getApkDigestSha256() != null) {
System.out.println("APK package name: " + stmt.getApkPackageName());
System.out.println("APK digest SHA256: " + Arrays.toString(stmt.getApkDigestSha256()));
System.out.println("APK certificate digest SHA256: " +
Arrays.deepToString(stmt.getApkCertificateDigestSha256()));
}
Now, run and you'll see the SHA-256 and let compare.
Not: there is no ":" charactor bettwen sha-256 generated cause i'm lazy. ^^.
Check the code here as reference on how to do the validations: https://github.com/Gralls/SafetyNetSample/blob/master/Server/src/main/java/pl/patryk/springer/safetynet/Main.kt
I just found it while searching for the same thing, and all credit goes to the person that owns the repo.
public class Starter {
static String keystore_location = "C:\\Users\\<your_user>\\.android\\debug.keystore";
private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
public static String bytesToHex(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2];
for (int j = 0; j < bytes.length; j++) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = HEX_ARRAY[v >>> 4];
hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
}
return new String(hexChars);
}
public static void main(String[] args) {
try {
File file = new File(keystore_location);
InputStream is = new FileInputStream(file);
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
String password = "android"; // This is the default password
keystore.load(is, password.toCharArray());
Enumeration<String> enumeration = keystore.aliases();
while(enumeration.hasMoreElements()) {
String alias = enumeration.nextElement();
System.out.println("alias name: " + alias);
Certificate certificate = keystore.getCertificate(alias);
System.out.println(certificate.toString());
System.out.println(certificate.getEncoded());
final MessageDigest md = MessageDigest.getInstance("SHA-1");
final MessageDigest md2 = MessageDigest.getInstance("SHA-256");
final byte[] der = certificate.getEncoded();
md.update(der);
md2.update(der);
final byte[] digest = md.digest();
final byte[] digest2 = md2.digest();
System.out.println(bytesToHex(digest));
System.out.println(bytesToHex(digest2));
byte[] encoded = Base64.getEncoder().encode(digest2);
System.out.println(encoded);
String checksum = Base64.getEncoder().encodeToString(digest2);
System.out.println(checksum); // This should match apkCertificateDigestSha256
}
} catch (java.security.cert.CertificateException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
Now Google depreciated SafetyAPI and Introduced PlayIntegrity API for attestation. PlayIntegrity Service provides the response as follows.
{
"tokenPayloadExternal": {
"accountDetails": {
"appLicensingVerdict": "LICENSED"
},
"appIntegrity": {
"appRecognitionVerdict": "PLAY_RECOGNIZED",
"certificateSha256Digest": ["pnpa8e8eCArtvmaf49bJE1f5iG5-XLSU6w1U9ZvI96g"],
"packageName": "com.test.android.safetynetsample",
"versionCode": "4"
},
"deviceIntegrity": {
"deviceRecognitionVerdict": ["MEETS_DEVICE_INTEGRITY"]
},
"requestDetails": {
"nonce": "SafetyNetSample1654058651834",
"requestPackageName": "com.test.android.safetynetsample",
"timestampMillis": "1654058657132"
}
}}
Response contains only certificateSha256Digest of the app (The sha256 digest of app certificates) instead of having apkDigestSha256 and apkCertificateDigestSha256.
How do we validate the received certificateSha256Digest at server?
If the app is deployed in Google PlayStore then follow the below steps
Download the App signing key certificate from Google Play Console (If you are using managed signing key) otherwise download Upload key certificate and then find checksum of the certificate.
public static Certificate getCertificate(String certificatePath)throws Exception {
CertificateFactory certificateFactory = CertificateFactory.getInstance("X509");
FileInputStream in = new FileInputStream(certificatePath);
Certificate certificate = certificateFactory.generateCertificate(in);
in.close();
return certificate;
}
Generate checksum of the certificate
Certificate x509Cert = getCertificate("<Path of file>/deployment_cert.der");
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] x509Der = x509Cert.getEncoded();
md.update(x509Der);
byte[] sha256 = md.digest();
String checksum = Base64.getEncoder().encodeToString(sha256);
Then compare checksum with received certificateSha256Digest
String digest = jwsResponse.tokenPayloadExternal.appIntegrity.certificateSha256Digest;
if(checksum.contains(digest)){
//
}
Node.js code for encryption
function encrypt(msg) {
try {
const public_key = fs.readFileSync(path.join(__dirname, 'PublicKey.pem'), 'utf8');
const encryptStr = crypto.publicEncrypt({
key: public_key,
padding: crypto.constants.RSA_PKCS1_PADDING
}, Buffer.from(msg,'utf8'));
let encryptString = encryptStr.toString('hex');
return encryptString;
} catch (e) {
console.log(e);
return false;
}
}
Android Code for decryption
public static String decryptStringWithPrivateKey(String s, String keyFilename) throws Exception {
Cipher cipher = Cipher.getInstance("RSA");
PrivateKey pkey = readPrivateKeyFromPem(keyFilename);
cipher.init(Cipher.DECRYPT_MODE, pkey);
String dec = new String(cipher.doFinal(Base64.getDecoder().decode(s)), "UTF-8");
return dec;
}
public static PrivateKey readPrivateKeyFromPem(String keyFilename) throws Exception {
byte[] keyBytes = Files.readAllBytes(new File(keyFilename).toPath());
String keyString = new String(keyBytes);
if (keyString.contains("BEGIN PRIVATE KEY")) {
return readPrivateKeyFromPem_PKCS8(keyFilename);
}
else if(keyString.contains("BEGIN RSA PRIVATE KEY")){
return readPrivateKeyFromPem_PKCS1(keyFilename);
}
throw new Exception("Unknown private key format in "+keyFilename);
}
I want to encrypt api on server side and decrypt the data on android device to avoid unauthorized access.
while decryption on android "Input byte array has incorrect ending byte at 172"
this one error are thrown.
In the NodeJS code the cipher text is hex encoded and in the Java code it is Base64 decoded. This must be made consistent, either Base64 or hex encoding on both sides.
Also, in the Java code, when instantiating the cipher, only the algorithm is specified. This results in a default padding being used, which e.g. on my machine (API 28, Android 9 Pie) corresponds to RSA/ECB/NoPadding. This is not compatible with the NodeJS side, which uses PKCS#1 v1.5 padding (besides that RSA without padding, so called textbook RSA, is insecure). Therefore, padding must also be specified in the cipher instantiation with RSA/ECB/PKCS1Padding.
Using a private key in PKCS#8 format and an own implementation of readPrivateKeyFromPem_PKCS8() both codes work on my machine if the two bugs mentioned above are fixed. However, the methods not posted could also contain flaws.
I want to achieve end to end encryption in my app and I want my Public key to be a string so that I can send it to server. Kindly tell me a way to convert public Key to string and vice versa.
Your main question seems to be "a java code to convert public key to string and vice versa" and this can be done with a few lines of code.
The full example code generates a RSA key pair, get the encoded form of the public key (as byte array) and encodes this in
Base64 encoding to a string. The encoding is done with the Android util class. Then the string needs to be transported to the
server, decoded to a byte array and this byte array runs into a key factory that "regenerates" the public key - voila.
Kindly note that the code has no exception handling and is for educational purpose only.
output:
Convert RSA public key into a string an dvice versa
publicKey: Sun RSA public key, 2048 bits
params: null
modulus: 18853651626448533042344052742185586831509096183921137436644620443732807152716528158465416708071104899767862289783079092216042499687784322092232163872332358586822678596223733228124113017356896219191227134298362353552882770945818159114272146532048929436504145362418430766823867890113522564795700689158702507402243560009550536419065620409534494384621580364502393563063483223294632627903706549112325066113361455750410642281763368591922729105346933211850575970566025026523917327761707615319008741255611490792106558703015066844972642677443110535667601315009551275389632601989979561472926080344790824117481932026867279062677
public exponent: 65537
publicKeyString: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlVmFPS+dIDcJILVZMM9hdQwEiLcHx7SVYF5gOrakPH7ZzilcOjWYcR47qktQAUu97JbLu3h3WPmm1nkgSXU1lVBoqc8pA1BHmzdvMK61A/F77nspDce0QqH5f5kQvYcuQrl+cCUvaTI/3/WBWwRIO2xGKMKRIgiBWDN/HVsqYU2O2pAJnLKQbz9NkkfGNVdzn4H21hi0shCVWCpt80zZkn0gm3oWtCGHOnyszXUOiw7inAdGkNGiZRyiFOUmFNRKLIYM3WiyU1NRGVrjto9NH/E53JdgSyBEu7kkWMLJqNuwj+DNQFu3Qq5VrNxwWggrwhFG+K0y0+Ed+scT003mlQIDAQAB
publicKeyServer: Sun RSA public key, 2048 bits
params: null
modulus: 18853651626448533042344052742185586831509096183921137436644620443732807152716528158465416708071104899767862289783079092216042499687784322092232163872332358586822678596223733228124113017356896219191227134298362353552882770945818159114272146532048929436504145362418430766823867890113522564795700689158702507402243560009550536419065620409534494384621580364502393563063483223294632627903706549112325066113361455750410642281763368591922729105346933211850575970566025026523917327761707615319008741255611490792106558703015066844972642677443110535667601315009551275389632601989979561472926080344790824117481932026867279062677
public exponent: 65537
code:
import android.util.Base64;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
public class Main {
public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeySpecException {
System.out.println("Convert RSA public key into a string an dvice versa");
// generate a RSA key pair
KeyPairGenerator keygen = KeyPairGenerator.getInstance("RSA");
keygen.initialize(2048, new SecureRandom());
KeyPair keyPair = keygen.generateKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();
System.out.println("publicKey: " + publicKey);
// get encoded form (byte array)
byte[] publicKeyByte = publicKey.getEncoded();
// Base64 encoded string
String publicKeyString = Base64.encodeToString(publicKeyByte, Base64.NO_WRAP);
System.out.println("publicKeyString: " + publicKeyString);
// ... transport to server
// Base64 decoding to byte array
byte[] publicKeyByteServer = Base64.decode(publicKeyString, Base64.NO_WRAP);
// generate the publicKey
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKeyServer = (PublicKey) keyFactory.generatePublic(new X509EncodedKeySpec(publicKeyByteServer));
System.out.println("publicKeyServer: " + publicKeyServer);
}
}
I'm using RSA encrypt text and decrypt text. The public key and the private key are generated with openssl tool.
I encountered an "java.lang.ArrayIndexOutOfBoundsException: too much data for RSA block" exception when decrypting data.
Here is the RSA util class:
package studio.uphie.app;
import android.util.Base64;
import java.security.KeyFactory;
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 javax.crypto.Cipher;
/**
* Created by Uphie on 2016/4/11.
*/
public class RSA {
private static String RSA = "RSA";
/**
*
* #param text text to be encrypted
* #param pub_key rsa public key
* #return encrypted data in byte-array form
*/
public static byte[] encryptData(String text, String pub_key) {
try {
byte[] data = text.getBytes();
PublicKey publicKey = getPublicKey(Base64.decode(pub_key.getBytes(), Base64.DEFAULT));
Cipher cipher = Cipher.getInstance(RSA);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return cipher.doFinal(data);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
*
* #param text text to be decrypted
* #param pri_key rsa private key
* #return
*/
public static byte[] decryptData(String text, String pri_key) {
try {
byte[] data = text.getBytes();
PrivateKey privateKey = getPrivateKey(Base64.decode(pri_key.getBytes(),Base64.DEFAULT));
Cipher cipher = Cipher.getInstance(RSA);
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return cipher.doFinal(data);
} catch (Exception e) {
//"java.lang.ArrayIndexOutOfBoundsException: too much data for RSA block" exception occurs here.
return null;
}
}
/**
*
* #param keyBytes
* #return
* #throws NoSuchAlgorithmException
* #throws InvalidKeySpecException
*/
public static PublicKey getPublicKey(byte[] keyBytes) throws NoSuchAlgorithmException, InvalidKeySpecException {
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(RSA);
return keyFactory.generatePublic(keySpec);
}
/**
*
* #param keyBytes
* #return
* #throws NoSuchAlgorithmException
* #throws InvalidKeySpecException
*/
public static PrivateKey getPrivateKey(byte[] keyBytes) throws NoSuchAlgorithmException,
InvalidKeySpecException {
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(RSA);
return keyFactory.generatePrivate(keySpec);
}
}
And the snippet that encrypts and decrypts data:
//encrypt
byte[] e = RSA.encryptData(text, PUBLIC_KEY);
String result = Base64.encodeToString(e, Base64.DEFAULT);
tv_encrypted.setText(result);
//decrypt
byte[] d = RSA.decryptData(text, PRIVATE_KEY);
String result = Base64.encodeToString(d, Base64.DEFAULT);
tv_decrypted.setText("Decrypted result:\n" + result);
I know the reason may be that the text to be decrypted is too long , but I just encrypt "abc" and then decrypt the encrypted "abc". And how to handle encrypting long text if the text to be encrypted or decrypted should be 11 bytes less than the rsa private key? How can I do to solve it? I'm new to RSA.
Thanks in advance!
You are missing some steps in your code which makes it impossible to check. However, there are a few clues to suggest a problem. Your decryptData method takes a String argument and then calls String.getBytes() to get the data which is then decrypted. However, the result of encryption is a sequence of bytes which is not the encoding of any valid String. Perhaps you meant to base64 decode the input instead of calling getBytes(). In general to perform decryption and decoding you must reverse the steps you performed during encryption and encoding. So, if the plaintext is a byte[] then the steps are:
byte [] → Encrypt → byte [] → Base64 encode → String.
then, in the decrypt direction you start with a Base64 string, you must, in order:
String → Base64 decode → byte [] → decrypt → byte []
Also, another issue which is bad practice and a source of many portability bugs is the use of defaults. You are using defaults in two places and they're both troublesome. First you are using the default no-args String.getBytes() method, and presumably matching that up with the one-arg String (byte []) constructor. This use the platform default character set, but this can differ on different platforms. Therefore always specify a character set. For most applications 'UTF-8' is an ideal choice. Secondly, you are calling Cipher.getInstance('RSA') without specifying padding. Oracle's Java and Android's Java will give you different padding and thus your code will not be portable between the platforms. Always specify the complete padding string. Here the choice is little more difficult if you need portability to older Java implementations. OAEP padding should be your first choice, so Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding"); is probably the right choice. See this for further discussion.
As for how to encrypt longer texts, see the answer from Henry.
Fianlly I modified my codes like that and they work well:
public static String encryptData(String text, String pub_key) {
try {
byte[] data = text.getBytes("utf-8");
PublicKey publicKey = getPublicKey(Base64.decode(pub_key.getBytes("utf-8"), Base64.DEFAULT));
Cipher cipher = Cipher.getInstance(RSA);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return Base64.encodeToString(cipher.doFinal(data),Base64.DEFAULT);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static String decryptData(String text, String pri_key) {
try {
byte[] data =Base64.decode(text,Base64.DEFAULT);
PrivateKey privateKey = getPrivateKey(Base64.decode(pri_key.getBytes("utf-8"),Base64.DEFAULT));
Cipher cipher = Cipher.getInstance(RSA);
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return new String(cipher.doFinal(data),"utf-8");
} catch (Exception e) {
return null;
}
}
If something seems wrong still you can remind me. Thanks for James and Henry's answer.
Usually, you generate a random secret key for a symmetric cipher (like AES) and use this to encrypt your pay load.
RSA is then only used to encrypt this random key. This does not only solve the length problem but has some other advantages as well:
Symmetric cyphers are usually much faster
If the message is sent to several recievers, only the encrypted key has to be added specifically for each receiver, the main content can be the same.
What can be achieved to this encrypted format?
My android app send encrypted messages to the c# server but server want encrypted messages actually like this unknown formatchinese words.
[![Unknown encrypted format ][1]][1]
But android encrypt messages like this format (on7vQhgNeVDVDu4evL0HZ5UbC2C1oZdamfU9XBLGZQZ13MLQKu2speIWNaldsfcGfPS)
I use RSA algorithm with same public/private keys in c sharp and android.
where am i interrupted?
Something wrong with this approach with this unknown format.
Its seems android have problem with class of encryption I don't know what else need to use for this issue
Thank you for advice
Android code
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.acti);
try {
generateKey();
} catch (Exception e1) {
e1.printStackTrace();
}
}
public static void generateKey() throws Exception {
String modulusString = "tx94IV9NAutFU1HQjXmkLzknJ5vatOFyhD90Un3u5oiOc4e9fT1bsM0af3OqNMCTRLPuQJ2JQokY+3T0icJqHgG/aHvbmvDvRKn2QrVxAFt8EN6jp/S6+dRe1B/6eJbVRJJpeekLslqGqdQgr+5ocD+ZPjiE2iL6sGGyAYz+lOJtSr9N4ZcD4kNikI3J9kZDNO78rEqQuX7flh0RS79N63MJ9xX9fBuqHFIud3KKKbqHiASQoaU1rWqZ2VIdqfXzreZMYHpHYioVzyrbk/wdQQV2ibmJFAsa5aiKSP+g9rF4xYoPAistePDwn4O+wARGlMsu7RYVAIeUM77l+w6ugw==";
String ExponentString = "AQAB";
byte[] modulusBytes = Base64.decode(modulusString.getBytes("UTF-8"), Base64.DEFAULT);
byte[] exponentBytes = Base64.decode(ExponentString.getBytes("UTF-8"),Base64.DEFAULT);
BigInteger modulus = new BigInteger(1, modulusBytes);
BigInteger publicExponent = new BigInteger(1, exponentBytes);
KeyFactory fact = KeyFactory.getInstance("RSA");
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING");
String INPUT = "GAVDOOL";
RSAPublicKeySpec rsaPubKey = new RSAPublicKeySpec(modulus, publicExponent);
PublicKey pubKey = fact.generatePublic(rsaPubKey);
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
// byte[] plainBytes = clearTextPassword.getBytes();
byte[] cipherData = cipher.doFinal(INPUT.getBytes());
String encryptedStringBase64 = Base64.encodeToString(cipherData, Base64.DEFAULT);
System.out.println("Encrypted?????"+encryptedStringBase64);
System.out.println(encryptedStringBase64.length());
}
}
Unknown encrypted format, see this at [1]: http://i.stack.imgur.com/hF84B.jpg
The method encrypt(data) is never called? Seems you have some unreachable code...
SOLVED,
I finally changed server code and remove the Encoding.Unicode part and now this issue is gone.