Using PHP/Python to verify ECDSA signature - php

I write the code to generate ECDSA signature on Android using spongycastle lib. Then I send the sign string and public-key to server (Ubuntu 16.04) and try to use php and python to verify this sign.
I test verify on my android app. It worked well.
I use php-openssl extension and with Python I use ecdsa 0.13. But, both of this failed. I try again, using openssl command and it can't verify too.
I don't know, where I am wrong.
Why is the ECDSA verification failing?
Here is my code:
Generate signature (android):
ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec("prime256v1");
try {
KeyPairGenerator g = KeyPairGenerator.getInstance("ECDSA","SC");
g.initialize(spec, new SecureRandom());
KeyPair keyPair = g.generateKeyPair();
privateKey = keyPair.getPrivate();
publicKey = keyPair.getPublic();
///write public key to pem file
......
FileOutputStream fileOutputStream1 = new FileOutputStream(file1);
StringWriter writer1 = new StringWriter();
PemWriter pemWriter1 = new PemWriter(writer1);
pemWriter1.writeObject(new PemObject("PUBLIC KEY",publicKey.getEncoded()));
pemWriter1.flush();
pemWriter1.close();
String publickeyPem = writer1.toString();
fileOutputStream1.write(publickeyPem.getBytes());
fileOutputStream1.close();
} catch (Exception e) {
e.printStackTrace();}
......
//Sign and veryfied
String chuoi = txtChuoi.getText().toString();
byte[] chuoiInput = chuoi.getBytes("UTF-8");
Signature sig = Signature.getInstance("NONEwithECDSA","SC");
sig.initSign(privateKey);
sig.update(chuoiInput);
///SIGN
byte[] signatureBytes = sig.sign()
txtMaHoa.setText(Base64.encodeToString(signatureBytes,Base64.DEFAULT));
sig.initVerify(publicKey);
sig.update(chuoiInput);
///VERIFIED
txtGiaiMa.setText(sig.verify(signatureBytes)+"");
///Write string sign in txtMahoa to file
.......
Output I have Signature and publickey are:
(Signature string) MEYCIQC7Hz631IFGsUOogcRLeN99uM9hWgLr+LGzuJvR/6nBrgIhAMXgZcvXyMRCAELXlNNS1a9j iAT1x0q2C5Mdu+2aZKtN
(Publickey)
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEj07XEM+ulPyrdsfAf9prN2L2dNUd /Yy0rABcFdueAwYUf86f8Cc93Ws6sxzIvf2iKOapFby7EjHewjhLM/z7Qg==
-----END PUBLIC KEY-----
Verify using PHP:
$pubkeyid = openssl_pkey_get_public("/var/www/html/ca.pem");
$data = "nguyen tran thanh Lam";
$signature =
"MEYCIQC7Hz631IFGsUOogcRLeN99uM9hWgLr+LGzuJvR/6nBrgIhAMXgZcvXyMRCAELXlNNS1a9jiAT1x0q2C5Mdu+2aZKtN";
$ok = openssl_verify($data, $signature, $pubkeyid);
if ($ok == 1) {
echo "good";
} elseif ($ok == 0) {
echo "bad";
} else {
echo "ugly, error checking signature";
}
?>

Comment: ... but the verify function don't return anything. So I not sure
If crypto.verify(... don't throw an Error, this means Verify is OK. See updated Code below.
Verify with using WRONG Certificat, Signature or Data.
Comment: what do you think about add base64.b64decode. ... because in android code I have this linetxtMaHoa.setText(Base64.encodeToString(signatureBytes,Ba‌​se64.DEFAULT));
PEM is already base64, check if the above .setText(Base64... can omitted. For now I have updated the Code below with base64.b64decode.
Question: Example ---- b"sha256"? "b" is a binary (built-in funtion or I must convert string sha256 to binary?)
Works for me only as String (digest-names), for example:
import pem, base64
from OpenSSL import crypto
signature = b"MEYCIQC7Hz631IFGsUOogcRLeN99uM9hWgLr+LGzuJvR/6nBrgIhAMXgZcvXyMRCAELXlNNS1a9jiAT1x0q2C5Mdu+2aZKtN"
# As Creator of the Signatur do additional base64 encoding!
signature = base64.b64decode(signature)
data = "nguyen tran thanh Lam"
certificate = pem.parse_file('Android.pem')[0]
cert = crypto.load_certificate(crypto.FILETYPE_PEM, certificate.as_bytes())
try:
crypto.verify(cert=cert, signature=signature, data=data, digest='sha256')
except crypto.Error as exp:
print('crypto.Error:{}'.format(exp.args))
>>>crypto.Error:([('', 'ECDSA_do_verify', 'bad signature')],)
Note: Throws crypto.Error because not using the certificate which created the signature.
OpenSSL.crypto.verify(certificate, signature, data, digest)
Verify the signature for a data string.
certificate is a X509 instance corresponding to the private key which generated the signature.
signature is a str instance giving the signature itself.
data is a str instance giving the data to which the signature applies.
digest is a str instance naming the message digest type of the signature, for example b"sha256".
New in version 0.11.

Related

JS encrypt then decrypt it with PHP

How to do I decrypt data using PHP that I have encrypted with using JSEcrypt
Following is how I encrypted my code
async function Encrypt(form = {}) {
const JSEncrypt = (await import("jsencrypt")).default;
let encrypt = new JSEncrypt();
encrypt.setPublicKey(publicKey);
let data = btoa(JSON.stringify(form));
let encrypted = encrypt.encrypt(data);
return encrypted;
}
When I decrypt it using JS, it works fine
async function Decrypt(encrypted) {
const JSEncrypt = (await import("jsencrypt")).default;
let encrypt = new JSEncrypt();
encrypt.setPrivateKey(privateKey);
let decrypted = encrypt.decrypt(encrypted);
return decrypted;
}
How do I do the same decrypt function in PHP ?
This is what I have tried and it does not work
function decrypt($data) {
$privateKey = file_get_contents("../keys/private_key.pem");
$key = openssl_get_privatekey($privateKey);
$data = base64_decode($data);
$result = openssl_private_decrypt($data, $decrypted, $key , OPENSSL_PKCS1_PADDING); //Keeps returning false
if ($result) {
# code...
$decrypted_data = base64_decode($decrypted);
return json_decode($decrypted_data);
}
return "No data";
}
PHP decrypt function returns "No data" because $result keeps returning a false value.
Thank you.
Sample Data that I am using
Blockquote
**Public Key**
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+QJEeRV7zs0Eh3W1/A1L
Bi9Rh8CXO8mdC1GICj3CUfUJ5xHoNGo03XsMZl7rU2szcmYh/T4Iidnr5hkZB/FG
RqmBy9xUA6IKTJANIkhuAGuzhkCXwnKiCjHBHr3HlqBq201BzPqw4+6+TMTmOe1p
DJ6xmy4YALqf5ovZ9HxJ9DcBzzuDgcNBTMcHAskGZexK3C66OJTFeDXqUS8VuYfa
robAuLeH/8LPnFfAKAYvoZQvUM0zvfn/VIJkvPbCeTr5RYvcpCj2t53tSBpaGKRa
EmiIfT3gKUraJDGz4BEtw7skc4Li3vZAt96UA6XoJdglphxwNztA1ZUaovVg2foN
EQIDAQAB
-----END PUBLIC KEY-----
**Private Key**
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQD5AkR5FXvOzQSH
dbX8DUsGL1GHwJc7yZ0LUYgKPcJR9QnnEeg0ajTdewxmXutTazNyZiH9PgiJ2evm
GRkH8UZGqYHL3FQDogpMkA0iSG4Aa7OGQJfCcqIKMcEevceWoGrbTUHM+rDj7r5M
xOY57WkMnrGbLhgAup/mi9n0fEn0NwHPO4OBw0FMxwcCyQZl7ErcLro4lMV4NepR
LxW5h9quhsC4t4f/ws+cV8AoBi+hlC9QzTO9+f9UgmS89sJ5OvlFi9ykKPa3ne1I
GloYpFoSaIh9PeApStokMbPgES3DuyRzguLe9kC33pQDpegl2CWmHHA3O0DVlRqi
9WDZ+g0RAgMBAAECggEBAO7twg39E0MnbYUc6XXku2w/0xdTMMnpdor5vHM3N1G0
sb/KauiAUCGEhC1mPp9YaZEHdu2rrD25oKS0yFPaqvf6hdS6oNKrlP5J6pBOt14n
+aaELBokLF9jxk5dAzoAyweKZeztTvYmiurWs6I5r2awjvK7k8R/ThbFcmkpKTzt
9oOvq2QoA+fCeqby63SAvl+KmQs3SCEYYQHAkNhwa6BvYTld6FbzL23BxZs2Zr5F
156X91D4lh1eAtgKW/Qq3O0y+Jgeff1VFYasVEsg26XjzY4cVzYtLjXT0SogKxEy
zQS0xPczkweN+LWNo0TzpKzfCdgqPIc5hxxUK+Aj8AECgYEA/KrkKPO0d+AJQoo3
/9ehf7DLKzvpa1qjdw8GI0w/XVzc1nt2YTziZgH1Rj+f17DqbEZFn8c2dl7Cqk7x
XVW16js92g265avovy745xTZ/GhG/4IvS12cZLggedV33RHXrZ035vy/Ahs/QAOJ
WIkV0u3fcopkIewPnJ/XlxWzCsECgYEA/EsF441w/r1FoYUQ8UqVKsFPsJLKLiGL
FNGyUvhoeI+DpBXAz4ZNYAILHYqOKoV60uZhg73FN0m5ihtgCBT7pnsSTkugDLsv
9zjkogdeRypN4Of/PIKUyylDJCGvIX+YmQ06STuH9H2lbvwg9E0/vElUVL+qC0Bj
UanVmb57JlECgYAVs6PnNI9yoGaLNY37xoyTiB7bNskktGNH7Z1sWLc0kK5TKcWQ
MoeLlW14vCxBfWuVIzAFujmeTyNPN3qZtqvqU25LlVRRN8PE8Abm6i6S9G3sskTX
p1GwgPQhIsmpzkeFHPTZPSo2xxpWqDcayKN8O3wuvV4+X6UzobMFwhJfwQKBgQCA
56AppOH/9hr2rPN8JZxTjRO3ZzjQGylhyMaxJ+TQ/JrJIqgyIC+2hzTAskNzLGIW
EcnvMu3qEswu6U/GsVnmtOkkgfVTq+yVB0eiFduwxsely0OY2itGJl38vw0pM3V3
dc+7DSSo4e296Cq6SCHxhRIGfytVtl9IoVrWxAFOEQKBgFmITpM9StkIHJqd/Lkb
gscOOHRpWd20lPos/n42LoIspz7zgbiEi2saiO+yZZ+xK56PYaGkAIyNvzqOVoKi
HBy3FrbxOc+EGIMemvVPv0rK0Jpz8vdgTmXf+4NbWu7jRCvQCrNbCflWyka/w438
mqlInSoviiAMRu2BcS2cojys
-----END PRIVATE KEY-----
Data Set 1
**Clear Text**
o4XuRo4Im3wkJImjLq96XvODUzR5Y+1GCqViKQqStyoidS8+9aQbLrWFpjhyHuE019YzJLHhuWxWlo7yfR3aebm5kObvq/QBe821dZgnOLtvdeUM4NP8iapjV945DsjRkp9g8vEwH3gGN0p/RrzWvbsF57OZ3eLRFjkFv2TS9PcUVlVHYbxpTjfhskpOQrDJeJJZjnCaRyPOa2VG4k3Y3p7WJzU+oT9DJK2aUscuS8zyDvLHSWvS09KOe/5xu+554Q54QHaLmAUxqu//4EjK+8yDko8Ji3mnmpFD0eyXfO2uMlw8dAUJ4w1++hNr7pr60K4rV47aCP1mh6za9lzmUg==
**Signature String**
7MC7xeKz+wbBTm1uxcKKV6AS3hM5TUS9T2ZWOxnxZNptBvClsoVktdfb8LVCTaDOKU9dopawZhcLl1fPZwHSoeQMhkkI2IRq9eHry4XWmXyDwSTLn+90AIdyxh+RuFrasGvcOmjRc75Eij393eDfl/MHyVeipIZXMUrWmRTgIjekXEffsoVrpuEGygGnltHMINXA+H1EbsFfJL4ok8zm4JhX8NdZSAcM3zeHrsf1DXbDRPOm4rwdZiuR5y4JGiVKXnEqfu3MA+tllQObE0UTngaUVVea5BFAjMYgE58cvYslzUbQAzKJERfABMg+LeBBuWTRPMrA4y+xKf8r2UHUBg==
Signature passes smoothly
Data Set 2
**Clear Text**
34JPmAmu4avmsBDL2A9t3NvC5ljfQgcLNNcEclXbTs+Efi6vj3QZb2eMjIA2uOKgBP3ChVJIAI4Zj9rjq31CmrRVtCMPPX5okgOVOH0wK/v+tScwW87SMWOdGhiBn+HXSYQQO3gpLYczVuD+RHzs5/7FEYSnyfg4aT+UTKDrkIxJFOdbdYUKB9zDeGFDiCqSgphU8qZdVoxAk+yCg5gec+/JnK4hrd209fj1tbE4vzFax9fW+jGscHsIn2Fr6gwpVs2zUAHYn8lbiTfI8ao3TJ2BE7aEkcwsq+SZAsKmWDFnwf7aUtZtr8pCkSvT6A/dMeH1Ib9tWl1A6KpczfHH6g==
**Signature**
x6mXZvdZggPBKxMtmnHIdw2j+7WJgfqfsc8udymJE+Z6tEonQvgr5RKr2OUdLUuYul13G/GCgkm+BpbensfsM7G7IwJenjCJs4FXgtYjLCG3QTLNz2OalgLy1dw1SyRW4XETmsbTZysjxvpaBh0/ggC/Dh2oYFsZYVRGDnFgQTWzmMfMIuq2cDT95MmUyN1wLjRxuiQD4vAowkmf5igJpaw1Bd9+ifT3K7LS9dtmq9bl3n1RKV9I7nWbTgT6qgujOsOwTpYjfuGT2xBuqBvDd+al4FPiMaVSt8oDVr5SLuClXYc9Ky+1OcXEgsjdyHqP7kio58PvitUa++q6m+i5bA==
Signature passes smoothly as well
These are my sample data . Hopefully, it is sufficient enough. Thank you
FULL PHP CODE
Decrypt.php
<?php
function decrypt($data) {
$privateKey = file_get_contents("../keys/private_key.pem");
$key = openssl_get_privatekey($privateKey);
$data = base64_decode($data);
$result = openssl_private_decrypt($data, $decrypted, $key,OPENSSL_PKCS1_OAEP_PADDING);
if ($result) {
# code...
$decrypted_data = base64_decode($decrypted);
return json_decode($decrypted_data);
}
return "No data";
}
?>
VerifySignature.php
<?php
include('./Decrypt.php');
$cert = file_get_contents("../keys/public_key.pem");
/**Run node index.js in terminal to get data & signature */
$data = "o4XuRo4Im3wkJImjLq96XvODUzR5Y+1GCqViKQqStyoidS8+9aQbLrWFpjhyHuE019YzJLHhuWxWlo7yfR3aebm5kObvq/QBe821dZgnOLtvdeUM4NP8iapjV945DsjRkp9g8vEwH3gGN0p/RrzWvbsF57OZ3eLRFjkFv2TS9PcUVlVHYbxpTjfhskpOQrDJeJJZjnCaRyPOa2VG4k3Y3p7WJzU+oT9DJK2aUscuS8zyDvLHSWvS09KOe/5xu+554Q54QHaLmAUxqu//4EjK+8yDko8Ji3mnmpFD0eyXfO2uMlw8dAUJ4w1++hNr7pr60K4rV47aCP1mh6za9lzmUg==";
$signature = "7MC7xeKz+wbBTm1uxcKKV6AS3hM5TUS9T2ZWOxnxZNptBvClsoVktdfb8LVCTaDOKU9dopawZhcLl1fPZwHSoeQMhkkI2IRq9eHry4XWmXyDwSTLn+90AIdyxh+RuFrasGvcOmjRc75Eij393eDfl/MHyVeipIZXMUrWmRTgIjekXEffsoVrpuEGygGnltHMINXA+H1EbsFfJL4ok8zm4JhX8NdZSAcM3zeHrsf1DXbDRPOm4rwdZiuR5y4JGiVKXnEqfu3MA+tllQObE0UTngaUVVea5BFAjMYgE58cvYslzUbQAzKJERfABMg+LeBBuWTRPMrA4y+xKf8r2UHUBg==";
$pubkeyid = openssl_pkey_get_public($cert);
//verify signature
$result = openssl_verify($data, base64_decode($signature), $pubkeyid,OPENSSL_ALGO_SHA256);
// $result = openssl_verify($data, $signature, $pubkeyid,OPENSSL_ALGO_SHA256);
if ($result == 1) {
# code...
var_dump("Valid Signature");
$decrypted = decrypt($data);
} else {
var_dump("Invalid Signature");
}
?>
Others have suggested to just lean on HTTPS, a few things to bare in mind:
HTTPS encrypts the communication between the client and the server using SSL/TLS protocols. This protects all data, including query strings in URLs, from being tampered with or intercepted while in transit.
Query strings in URLs are sent as regular text as part of the request, but when HTTPS is used, the entire request, including the query strings, are encrypted, making them secure during the transmission.
Now to your problem...
Assuming your public key is definitely married to your private key.
OpenSSL functions are typically used to decrypt payloads from OpenSSL functions, whilst both OpenSSL and JSEncrypt use the RSA algorithm, it's fair to say that their implementation may be different.
You could try using phpseclib
composer require phpseclib/phpseclib
<?php
use phpseclib3\Crypt\PublicKeyLoader;
function decrypt($encrypted)
{
$privateKey = file_get_contents('/path/to/your/private.key');
/** #var \phpseclib3\Crypt\RSA\PrivateKey $loader */
$loader = PublicKeyLoader::loadPrivateKey($privateKey);
$decrypted = $loader->decrypt(base64_decode($encrypted));
return json_decode(base64_decode($decrypted), true);
}
Disclaimer: Code above is untested

How do I use an already given private key as a private key resource in PHP?

I am working on integrating the Walmart API. They require a digital signature with each API call. My code seems to be working up until I have to deal with the private key. Here is my function to generate a digital signature:
//Most of this code is from a Walmart API sample
function _GetWalmartAuthSignature($URL, $RequestMethod, $TimeStamp, $ConsumerId) {
$WalmartPrivateKey = {given PEM formatted string};
//Construct the authentication data we need to sign
$AuthData = $ConsumerId."\n";
$AuthData .= $URL."\n";
$AuthData .= $RequestMethod."\n";
$AuthData .= $TimeStamp."\n";
//THIS METHOD IS RETURNING FALSE!!!!
$PrivateKey = openssl_pkey_get_private($WalmartPrivateKey);
//Sign the data using sha256 hash
defined("OPENSSL_ALGO_SHA256") ? $Hash = OPENSSL_ALGO_SHA256 : $Hash = "sha256";
if (!openssl_sign($AuthData, $Signature, $privKey, $Hash)) {
return null;
}
//Encode the signature and return
return base64_encode($Signature);
}
The openssl_pkey_get_private() func keeps returning false. So then my openssl_sign() func gives me the error: openssl_sign(): supplied key param cannot be coerced into a private key
I tried first creating a new key resource, using
$res = openssl_pkey_new();
openssl_pkey_export($res, $privKey);
and then saving my $WalmartPrivateKey to $privKey, but I got the same error. I tried using openssl_get_private_key(), but again- nothing worked.
I only know the very basics of public/private key encryption, and this is my first time using these functions.
Can anyone help me out?
I had a similar issue, and it was because the PEM format was wrong. Make sure you have the correct beginning and ending markers:
"-----BEGIN PRIVATE KEY-----", "-----END PRIVATE KEY-----".
Both markers must have exactly 5 dashes before and after the words, and the words must be all caps.
Good luck!

swift sodium Decrypt using Private Key

I am using Swift Sodium on client side as my server is using libsodium to encrypt the data before sharing it with me through API.
Now I have a existing private key and a public key in a String format with me. I want to now decrypt the encrypted data at my end on iOS using Swift.
How do I generate a Sodium Key Pair using the public and private key that I have?
Also Ideally I should use only the private key to decrypt the data. So how do I do that using only private key as String.
My Code for decryption is shown below -
func decryptData(dataString: String) -> String? {
let sodium = Sodium()
let privateKey = sodium?.utils.hex2bin("MY_SECRET_KEY")
let publicKey = sodium?.utils.hex2bin("MY_PUBLIC_KEY")
let message = dataString.data(using: .utf8)!
if let decrypted = sodium?.box.open(anonymousCipherText: message, recipientPublicKey: publicKey!, recipientSecretKey: privateKey!){
// authenticator is valid, decrypted contains the original message
return String(data: decrypted, encoding: String.Encoding.utf8) as String!
}
return nil
}
In the above Code my decrypted String is always empty.
The server is encrypting the data using the below function -
protected function crypt($response)
{
$message = new HiddenString($response);
$repository = \App::make(EncryptionKeysRepository::class);
$enc = $repository->findOneBy(['device' => 'android']);
$dir = $enc->getDevice();
$publicKey = $enc->getPublicKey();
$storage = storage_path();
if(!file_exists($storage."/{$dir}/")) {
mkdir($storage."/{$dir}/");
}
// save key pair to key store
$pubFilename = \tempnam($storage."/{$dir}/", 'pub_key');
file_put_contents($pubFilename, $publicKey);
$public = KeyFactory::loadEncryptionPublicKey($pubFilename);
unlink($pubFilename);
rmdir($storage."/{$dir}/");
$message = Crypto::seal($message, $public);
return $message;
}
Decrypting Logic at server
protected function deCrypt($response)
{
$repository = \App::make(EncryptionKeysRepository::class);
$enc = $repository->findOneBy(['device' => 'android']);
$dir = $enc->getDevice();
$publicKey = $enc->getSecretKey();
$storage = storage_path();
if(!file_exists($storage."/{$dir}/")) {
mkdir($storage."/{$dir}/");
}
// save key pair to key store
$secFilename = \tempnam($storage."/{$dir}/", 'sec_key');
file_put_contents($secFilename, $publicKey);
$secret = KeyFactory::loadEncryptionSecretKey($secFilename);
unlink($secFilename);
rmdir($storage."/{$dir}/");
$res = Crypto::unseal($response, $secret);
$message = $res->getString();
return response()->json(compact('message'));
}
So, server-side, you're apparently using PHP, with a library called Halite.
I'm not very familiar with Halite, but looking at its code, Crypto::seal() uses sealed boxes, so Box::open(anonymousCipherText: Data, recipientPublicKey: PublicKey, recipientSecretKey: SecretKey) -> Data? is the correct method to decrypt this in Swift.
However, Halite also seems to encode the result as a BASE64 string (urlsafe variant).
So, you need to decode this first. Or, and this is going to be way more efficient, do not encode the ciphertext. Unless you have to read them aloud, the keys probably don't need to be encoded either.

Decrypting a Base64 encrypted image in Android

Im trying to decrypt a text sent from the server to an android application.
On PHP, I have the following:
$rsa = new Crypt_RSA();
$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
$rsa->setPrivateKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS1);
$rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_PKCS1);
$key = "-----BEGIN PUBLIC KEY-----\n" . ($PublicKey)
. '-----END PUBLIC KEY-----';
$rsa->loadKey($key);
$base64 = 'data:image/' . $type . ';base64,' . base64_encode($data);
$imageEncrypt = base64_encode($rsa->encrypt($base64));
The encoding and the encryption work well.
When I send the encrypted text to android, i cannot decrypt. I used the code:
public static String decryptString(String alias,String cipherText) {
try {
KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry)keyStore.getEntry(alias, null);
// RSAPrivateKey privateKey = (RSAPrivateKey) privateKeyEntry.getPrivateKey();
Cipher output = Cipher.getInstance("RSA/ECB/PKCS1Padding");
output.init(Cipher.DECRYPT_MODE, privateKeyEntry.getPrivateKey());
CipherInputStream cipherInputStream = new CipherInputStream(
new ByteArrayInputStream(Base64.decode(cipherText, Base64.DEFAULT)), 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();
}
String finalText = new String(bytes, 0, bytes.length, "UTF-8");
return finalText;
//decryptedText.setText(finalText);
} catch (Exception e) {
Toast.makeText(context, "Exception " + e.getMessage() + " occured", Toast.LENGTH_LONG).show();
Log.e("DecryptStringTAG", Log.getStackTraceString(e));
}
return "EMPTY";
}
The error is:
java.io.IOException: Error while finalizing cipher
Caused by: javax.crypto.IllegalBlockSizeException
The odd thing is that when i try to send from PHP a message like "Hello", android decrypts it successfully. But when i send the encrypted image, I get the stated error.
I've been struggling to find the error.
Any help?
Thanks
RSA asymmetric key encryption which is what public key encryption uses, that is RSA is essentially public key encryption. If you must use public/private key pair encryption the answer is hybrid encryption, similar to what SSL does.
Create a random symmetric key use it to encrypt the data with AES. Then encrypt the symmetric key with the RSA public key.
On decryption first decrypt the symmetric key with the RSA private key and use that to decrypt the data with the symmetric AES.
If you are looking for secure encryption you really need to get someone who is a domain expert to at least design and vett the implementation. Security is very hard to get right, if it isn't right is provides no security.

openssl_private_decrypt does not return anything PHP

Updates:
openssl_error_string() gives:
error:0407106B:rsa routines:RSA_padding_check_PKCS1_type_2:block type is not 02
error:04065072:rsa routines:RSA_EAY_PRIVATE_DECRYPT:padding check failed
I generate a pair of public key and private key using OpenSSL on my server:
$config = array(
"private_key_bits" => 2048,
"private_key_type" => OPENSSL_KEYTYPE_RSA,
);
$res = openssl_pkey_new($config);
I sent the Base64-encode modulus and exponent to my Android client. My Android client reconstruct the public key from the modulus and exponent received. My Android client then encrypt a message using such key. Lastly, my Android client sends back to the server the encrypted message expecting the server to be able to decrypt it.
I have a simple PHP script on my server to test the decryption of the encrypted message from my Android client:
$sms_message = $argv[1];
$sender_no = $argv[2];
echo "Message received was: '$sms_message' \n";
echo "sender's no was: $sender_no \n";
$parts = array();
$parts = explode(" ", $sms_message);
if (count($parts)==2) {
echo "code: $parts[0] \n";
if (strcmp($parts[0], "smscode")==0) {
echo "measurement: $parts[1] \n";
// retrieve the private key
$keyArr = array();
$keyArr = getKeys();
//
if ($keyArr) {
$privateKey = $keyArr["private"];
echo "$privateKey \n";
// use the private key to decrypt the message
echo openssl_private_decrypt(base64_decode($parts[1]), $decrypted, $privateKey); // this is supposed to return either TRUE or FALSE right?
echo $decrypted;
$decryptedMessages = "decrypted.txt";
if (!$fh = fopen($decryptedMessages, 'a')) {
echo "cannot open file $decryptedMessages";
exit;
}
// Write $somecontent to our opened file.
if (fwrite($fh, $decrypted) === FALSE) {
echo "Cannot write to file ($decryptedMessages)";
exit;
}
//
fclose($fh);
}
} else {
echo "what received is not a measurement - $parts[1] \n";
}
} else {
echo "sms message malformed";
}
I ran the following:
php SmsReceiver.php 'smscode adDmHJDFmI8bC9KRcA7nPbTc2NU0sY7iM5jDHt3qJVq/AAyl9thUB3zVH5/9Jr+pTM4V+dift6UD8uB3nEU53thrY7nx55PsackCYzmBoKYTE4tazsyF7tRfAIawxvmR4lcSfKL2+A0N9ZetISoqqZAHI141n47Wtd52n0pE9tdLRGzXQlfeDOC3ntnbOKcIIhbyJWekLg+58uCLm2nfWPA4EveAd7t6RQPX4E20wXXQ1RgkVPCQsW+9WDdrbxav6y0VN7uKoBqA4/G8zn3Ol41OPtFFllBgl1BGUFWK3xcxxxZqodTCc3pTdAIHgJ4td+pktUjfbAwITt/RMC+IcA==' +6511111111
Message received was: 'smscode adDmHJDFmI8bC9KRcA7nPbTc2NU0sY7iM5jDHt3qJVq/AAyl9thUB3zVH5/9Jr+pTM4V+dift6UD8uB3nEU53thrY7nx55PsackCYzmBoKYTE4tazsyF7tRfAIawxvmR4lcSfKL2+A0N9ZetISoqqZAHI141n47Wtd52n0pE9tdLRGzXQlfeDOC3ntnbOKcIIhbyJWekLg+58uCLm2nfWPA4EveAd7t6RQPX4E20wXXQ1RgkVPCQsW+9WDdrbxav6y0VN7uKoBqA4/G8zn3Ol41OPtFFllBgl1BGUFWK3xcxxxZqodTCc3pTdAIHgJ4td+pktUjfbAwITt/RMC+IcA=='
sender's no was: +6511111111
code: smscode
measurement: adDmHJDFmI8bC9KRcA7nPbTc2NU0sY7iM5jDHt3qJVq/AAyl9thUB3zVH5/9Jr+pTM4V+dift6UD8uB3nEU53thrY7nx55PsackCYzmBoKYTE4tazsyF7tRfAIawxvmR4lcSfKL2+A0N9ZetISoqqZAHI141n47Wtd52n0pE9tdLRGzXQlfeDOC3ntnbOKcIIhbyJWekLg+58uCLm2nfWPA4EveAd7t6RQPX4E20wXXQ1RgkVPCQsW+9WDdrbxav6y0VN7uKoBqA4/G8zn3Ol41OPtFFllBgl1BGUFWK3xcxxxZqodTCc3pTdAIHgJ4td+pktUjfbAwITt/RMC+IcA==
private key found
public key found
-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC7dArHUiEXpEwi
...
F/EaVVWEZLevTJEdMpkfvQVr/08AlSLR3Nm33CrvQ1SfFygK0F6G6o1pQtnHlCKh
DK8/dT2CgsFuDbiAs4MRqQA36g==
-----END PRIVATE KEY-----
As you can see, openssl_private_decrypt() does not return anything, why?
Even if something is wrong with my encrypting/ decrypting process, at least give a false I'd expect.
Based64-encoded modulus of the public key:
u3QKx1IhF6RMIvncMADBhGqhdlSWnuuUz0dXr9NUzXJtgfPgvX/07w1IKTls6uj48eZ4J3s5me4xUzoRwIsxjk6Ondke2vGVJgzBZh3KQSml0dQoK/0a3Bc/bHwue3jroCCAaC/4lF6GQS5gB1gDQntkKBM+RaHaEqGldKHmF1T8Sg1zSLAU9IGBc+xDSCqgo2RepntB0npctBGmAYF8gdzN1PnAwgVfOLU/xi08ssQL1ppkrMncgPegaOOkyUZm4BXSyEY9ikYynLfoiQqEAFb9mU40yNM7LQusgqF0YhUgUIg+4fuQNscZJCJ6pS9UTQ64MHWCqrpXCeRAZ4rWeQ==
Based64-encoded exponent of the public key:
AQAB
Private key:
-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC7dArHUiEXpEwi
+dwwAMGEaqF2VJae65TPR1ev01TNcm2B8+C9f/TvDUgpOWzq6Pjx5ngnezmZ7jFT
OhHAizGOTo6d2R7a8ZUmDMFmHcpBKaXR1Cgr/RrcFz9sfC57eOugIIBoL/iUXoZB
LmAHWANCe2QoEz5FodoSoaV0oeYXVPxKDXNIsBT0gYFz7ENIKqCjZF6me0HSely0
EaYBgXyB3M3U+cDCBV84tT/GLTyyxAvWmmSsydyA96Bo46TJRmbgFdLIRj2KRjKc
t+iJCoQAVv2ZTjTI0zstC6yCoXRiFSBQiD7h+5A2xxkkInqlL1RNDrgwdYKqulcJ
5EBnitZ5AgMBAAECggEBAIoCAzWAF/EJ+yv8/MkypUbSIpG18TaLhwGcKsi+ND8V
sd3tKVca779X7fq71p6Ua0PdRDT9GglkPlhh9lPlptR4rbM0+OyE1CQxW+nMoO2c
tgJnyjOooq/LRdyfCLHK8t7vTtpmBwNlHD683+JIQA4gPjrq//vQD3eMHv5he79M
hbZVy93gI4x1FIQD8NPgJY3WX1tSojyOaSJCkR7cy3LjdsV17nNDTtJf5PhA584x
lJGjI6fX6VgiGhP8vmxkYYxFVzz2HrblMVodO95HKDwk/1RXvwqWFA72KQTBwLo7
iJpjP8k95FVys+KKHKbuAhbPhtzjmuRHCPSJ4zxFbEkCgYEA4vS2h5JqhlKzKi/v
i0lhei+HcTT53aUzCYA0qbBwJxvPZapi7lij7n2EeE5ZxGR4uPfUU71a1mrKrT6j
8XH0DxoxLT79jdiISG09rg0srnb/+EF7BKcSY4aQJwz/StAS7lxXySAatw2tVubv
MheSVyy1HaI0AE6fBBkt9VKNXv8CgYEA03Evu1Ycdlbi3mgS+hrxd0eabh5rETij
1jqEpiT/v7SPr1JNy3RwYXlEy7Y7e4lW3Wf7CsEV3Em/+vQNU3jA/7Sfqh5oyZoZ
o26tA8NyEpkiPhipAs8NfubUMLZGJKAhhrJo9vr4JzX866YVWlqEDqQ1lGuLJJOt
1DtZIxOAQocCgYEAido4EGrXt1T+LG7HYmQlCDFcZF/YMU/Ji0jLNBLOXILg25C9
3KYMlKy6zNRSZB7e0QL/fgmy5jAhgU9eBya/JnkzS5dKLWFLjiqEX3bzH9l6KtGj
JjVQzxEJ+B5F5qwyA4Qlci3E7FEra3CD83or0jV+oUxHp7QZlESzDKKi6gMCgYEA
irimvTy4vbcxbwNO+AH3S++RVQ/l5M2JSALqhmqd1DNtVXQlEAebt4etaA1uJxWr
BOW0YZDee8FzD/1QRORjkx/45M7ApwvQKFZzcpWm4KbRPXZGZE5dp1Vf/3mGuX7J
oCqrDOcJKgiUoDI9riLWoxh/ApowFtZA5I3vZEDmFD8CgYAnHOCZZI0IaieEcnRA
4vOu62y8VNut/18HIw9P/MD4ZbWXURnFzuzCUdHcw3vucFNjFSUjVMFZWo+Grxpq
F/EaVVWEZLevTJEdMpkfvQVr/08AlSLR3Nm33CrvQ1SfFygK0F6G6o1pQtnHlCKh
DK8/dT2CgsFuDbiAs4MRqQA36g==
-----END PRIVATE KEY-----
Android logcat:
I/SmsReceiver(15814): message received is keyx u3QKx1IhF6RMIvncMADBhGqhdlSWnuuUz0dXr9NUzXJtgfPgvX/07w1IKTls6uj48eZ4J3s5me4xUzoRwIsxjk6Ondke2vGVJgzBZh3KQSml0dQoK/0a3Bc/bHwue3jroCCAaC/4lF6GQS5gB1gDQntkKBM+RaHaEqGldKHmF1T8Sg1zSLAU9IGBc+xDSCqgo2RepntB0npctBGmAYF8gdzN1PnAwgVfOLU/xi08ssQL1ppkrMncgPegaOOkyUZm4BXSyEY9ikYynLfoiQqEAFb9mU40yNM7LQusgqF0YhUgUIg+4fuQNscZJCJ6pS9UTQ64MHWCqrpXCeRAZ4rWeQ== AQAB
I/SmsReceiver(15814): message received is a key exchange message
I/SmsReceiver(15814): the recipient's public key modulus is 23663785522794809498963221782819553495813344590754203802091214078741934630870755737273483338578650343553350487999568641527155675069988138202941338180146715141856273325699348180697949807604837968252319802254132361756796150729526732643616381939360742823851037800072915016799286519177887771453765989612342846498554824903381084855033387403868553674907286294016751397407403976788809972626838594376008433688839811350345997686592001128890405964489889151586297624459113817319199310865303723716614014342885058854916172119790960266134365108047747227357851477353947042531226823494283658181608350838513970607286067323054395676281 and exponent is 65537
I/SmsReceiver(15814): successfully remembered the contact +6500000000 and its public key module u3QKx1IhF6RMIvncMADBhGqhdlSWnuuUz0dXr9NUzXJtgfPgvX/07w1IKTls6uj48eZ4J3s5me4xUzoRwIsxjk6Ondke2vGVJgzBZh3KQSml0dQoK/0a3Bc/bHwue3jroCCAaC/4lF6GQS5gB1gDQntkKBM+RaHaEqGldKHmF1T8Sg1zSLAU9IGBc+xDSCqgo2RepntB0npctBGmAYF8gdzN1PnAwgVfOLU/xi08ssQL1ppkrMncgPegaOOkyUZm4BXSyEY9ikYynLfoiQqEAFb9mU40yNM7LQusgqF0YhUgUIg+4fuQNscZJCJ6pS9UTQ64MHWCqrpXCeRAZ4rWeQ== and exponent AQAB
OpenSSL asymmetric cryptography is not suitable for encrypting large files unless you use S/MIME. In fact, this is what I tried:
Decoded the base64-encoded 'measurement:' field. The decoded message was 256 bytes in length.
Tried to decrypt this 256 bytes with the private key that you pasted using the following openssl command:
openssl rsautl -decrypt -in x.in -out plaintext -inkey private.key
But, I got an error instead:
RSA operation error
139982152128160:error:0407106B:rsa routines:RSA_padding_check_PKCS1_type_2:block type is not 02:rsa_pk1.c:190:
139982152128160:error:04065072:rsa routines:RSA_EAY_PRIVATE_DECRYPT:padding check failed:rsa_eay.c:616:
In fact, I tried this using PHP itself. But, instead of doing an echo of $decrypted, I used openssl_error_string and it gave me the exact above error.
Also, I wasn't able to encrypt a 256 byte data with public key as well. I got error from openssl indicating 139870762710688:error:0406D06E:rsa routines:RSA_padding_add_PKCS1_type_2:data too large for key size:rsa_pk1.c:151:.
All of this seems to indicate that OpenSSL's asymmetric cryptography is not meant for encrypting large data (in this case, 256 bytes is large enough). I am not sure how the Android client was able to encrypt it. Did it use OpenSSL as well?
However, there are relevant posts on how to deal with this. Take a look at:
how to encrypt a large file in openssl using public key
Encrypt with S/MIME: http://ashmek.weebly.com/1/post/2011/02/encrypt-large-files-with-a-public-key-via-openssl.html

Categories