JS encrypt then decrypt it with PHP - 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

Related

crypto.publicEncrypt equivalent in PHP

Im trying to encrypt a string from a PHP application to a NodeJS API using a public key.
So far in node I am using the built-in crypto library and have the following code to decrypt a string:
decrypt(toDecrypt): string {
const buffer = Buffer.from(toDecrypt, "base64");
const decrypted = crypto.privateDecrypt(
{
key: this.privateKey,
passphrase: this.passphrase
},
buffer
);
return decrypted.toString("utf8");
}
I have been looking for a while now and cannot find an equivalent PHP code that will run through the node application and decrypt correctly.
My keys are generated using:
const keys = await generateKeyPairSync("rsa", {
modulusLength: 4096,
publicKeyEncoding: {
type: "spki",
format: "pem"
},
privateKeyEncoding: {
type: "pkcs8",
format: "pem",
cipher: "aes-256-cbc",
passphrase: this.passphrase
}
});
EDIT:
The PHP code that I am using currently:
<?PHP
$text = "TEST";
$key = "-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA6x5nGicq8jWbjRfeCot3
83M9Jo6wzhVAX9kKvIaKA51dR60qKKVXc8rJ3mWJIBsnWmEy1/QZ4BtEZ13ISFbt
DMzwMfV99hD12XqCvU1b45l//87Rqs1rE+7G90mW53mq5u2jmP/+7SCX+5r9ASLX
pJOoXRIpJpJhh/molv0PxS9b5c7nkrhGhpgQ1QeUSc3Q25kFP5PbAhphx08/M/KO
MaeBn+W4mhdS4Pt1Wgqa0T5PKkzr/uHd68f7IDqYWNKC9dMg0J2Rw8mo7g4L1oid
k/GkHk0UcSAe6FY5dsExgTMAEYwW7ngbPEQ8/BofGHWSnNVDFvuDxjCHAp+IEYa7
s3f+YmKqjoDDHkmx5kCYHYi+BK/gba3CLRfbvzlcd2YjOZZ8Mvd+1CBzYK5blyDv
Sefz8Kj+qmMOV9P4B9x4yVHGA57+vGmSbpEkdVUVd3JaazZFBSaiI8yQPeeljjze
0GH3V0BAPi3awCHVLYnbUJ1s0Q40RrEvWZQNjHGm17oHM0yfzgMUldJmUD6XGSOO
jJbfyAR4/TizosVedQ9CazTAogzFyqUtP74dzcNeHezKHz9ILngYTYuUT8p+wEIT
KejP5QqD/yumtUTNOYS/5fTvuTa7e97m0SgjlNHikol/DPcjz5RTf/tLxyVAft7I
3X5yUC7gDLdXBONMzhIA8YsCAwEAAQ==
-----END PUBLIC KEY-----";
$publicKey = openssl_pkey_get_public($key);
$output = "";
openssl_public_encrypt($text, $output, $publicKey, OPENSSL_PKCS1_OAEP_PADDING);
echo base64_encode($output) . PHP_EOL;
EDIT2:
What PHP Script gives me:
PVtIhXVoG3IeM2VrzihDTqRvUADMZLK7qCjNkRtrOqgn1XVOsXXMijxaJc65UjCM/37ceMafdek2V9fxcUP7f1LvaBPGhZtDkZFcBBekrvM/oeMmA2U0UUIDu2SMHR8pLjl7kQLUIF8unjDiHW0PgylqC9e/6Z/ptFhlsQTJE7RJdW8euQUJV3CaNKOriRe+QJe1T7QV0OZ+Omi1PuRp0CA383BDmadWflEhVe6tXaTKSlLpSE+nT2vqJa+7I3brzXAspWgwVjabxSEteMLmH0SCybiQBp6bs2l0CoD88QoNMidIs+ktI+h5uy2vcWZzFCYq5I77r+Pola9xTDqDWuDYNuejCPOR4D5mb4GauIymATioUW0hRtJYBFJh2dbogDz+UNtzzaIUKwt8rd9vTM1v+KQpXmakwcnaqpIWedhl8/eGv0DQcVzcUABg6SbCRyvfESYljrLzmbc0kLFWp12Ov2AU9G7MXUIY0DCidS/VgHmFNnfPJvJ0HiVpilGGb2kfOpzP3Eoqy786Fd5IbAcCSNkRkLXGEEvHS3L7TnckqW28WAC2dt2HsEINx0s4Iu75n7tuTUwIZD7xCp0BGUW7tcnS3ZX8mcggfSp04mFhPpS3z1UU7m/iY3Xs0pkzlKAHfz7A518p2O4RsChEwVy0Us9cwjFfOCaBxQT/UxE=
Error that Node gives me:
Can somebody please help?
Thanks,
Joe

What is the right algorithm for digitally signing in C and veryfing in PHP?

I'm trying to digitally sign files/messages in C and verify the signature in PHP.
I can verify it correctly in C, but when I try to import the signature and verify it in PHP it fails.
I'm signing the message in C using this method:
bool RSASign( RSA* rsa,
const unsigned char* Msg,
size_t MsgLen,
unsigned char** EncMsg,
size_t* MsgLenEnc) {
EVP_MD_CTX* m_RSASignCtx = EVP_MD_CTX_create();
EVP_PKEY_assign_RSA(privkey, rsa);
if (EVP_DigestSignInit(m_RSASignCtx,NULL, EVP_sha256(), NULL,privkey)<=0) {
return false;
}
if (EVP_DigestSignUpdate(m_RSASignCtx, Msg, MsgLen) <= 0) {
return false;
}
if (EVP_DigestSignFinal(m_RSASignCtx, NULL, MsgLenEnc) <=0) {
return false;
}
*EncMsg = (unsigned char*)malloc(*MsgLenEnc);
if (EVP_DigestSignFinal(m_RSASignCtx, *EncMsg, MsgLenEnc) <= 0) {
return false;
}
EVP_MD_CTX_free(m_RSASignCtx);
return true;
}
As I said, it's working fine if I try to validate this signature only in C.
The private key is obtained earlier in the code with this line of code:
pin = (char *) getpass("Enter PIN: ");
rc = PKCS11_login(slot, 0, pin);
authkey = PKCS11_find_key(&certs[0]);
If it's necessary I can post the code on how I get the slot, but I don't think it's necessary for now.
I'm trying to validate the signature in PHP using this code:
function isOriginal() {
$signature = base64_decode("HZwn2Zz4ir5Isvvo+fEj8IFydQs/tuW3I6HPzadHMIq+i5qCBURXqK/B5X1gYyoCPyHzgyY/zJI1skoFdKwPwx6ySEwLBZ5QTFsxp56jGi/UZgXu8X+jfvHfss89VhqcIxiZdklhZtlf5sMdJ045KbfvHDeAyfXj2C/3Nvk8IQMR+q3eUGAkiEZJIWpivp5WufrjFlsmKRdDm8j2szJPtIVipyj1AwIYkiAJOggC4JWd3LWn8C4bt84ys2CezFbc7BDckLe2IGBkaDMsCTr8PE0SP81npqHd9CyfvU4zd5LyXkBNZqz3QnAN19iI0b5EdUeJj3UQ83gmuugGy1088g==");
$publicRSAKey = "-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy8Dbv8prpJ/0kKhlGeJYozo2t60EG8L0561g13R29LvMR5hyvGZlGJpmn65+A4xHXInJYiPuKzrKUnApeLZ+vw1HocOAZtWK0z3r26uA8kQYOKX9Qt/DbCdvsF9wF8gRK0ptx9M6R13NvBxvVQApfc9jB9nTzphOgM4JiEYvlV8FLhg9yZovMYd6Wwf3aoXK891VQxTr/kQYoq1Yp+68i6T4nNq7NWC+UNVjQHxNQMQMzU6lWCX8zyg3yH88OAQkUXIXKfQ+NkvYQ1cxaMoVPpY72+eVthKzpMeyHkBn7ciumk5qgLTEJAfWZpe4f4eFZj/Rc8Y8Jj2IS5kVPjUywQIDAQAB-----END PUBLIC KEY-----";
$plaintext = "My secret message.";
$id = openssl_pkey_get_public(MY_PUB_CERT_IN_A_CONST_STR);
echo (openssl_verify($plaintext, $signature, $id, OPENSSL_ALGO_SHA256) ? 'verified' : 'unverified');
}
This fails. I've also tried to use PHPSECLIB:
function isOriginal() {
$signature = base64_decode("HZwn2Zz4ir5Isvvo+fEj8IFydQs/tuW3I6HPzadHMIq+i5qCBURXqK/B5X1gYyoCPyHzgyY/zJI1skoFdKwPwx6ySEwLBZ5QTFsxp56jGi/UZgXu8X+jfvHfss89VhqcIxiZdklhZtlf5sMdJ045KbfvHDeAyfXj2C/3Nvk8IQMR+q3eUGAkiEZJIWpivp5WufrjFlsmKRdDm8j2szJPtIVipyj1AwIYkiAJOggC4JWd3LWn8C4bt84ys2CezFbc7BDckLe2IGBkaDMsCTr8PE0SP81npqHd9CyfvU4zd5LyXkBNZqz3QnAN19iI0b5EdUeJj3UQ83gmuugGy1088g==");
$publicRSAKey = "-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy8Dbv8prpJ/0kKhlGeJYozo2t60EG8L0561g13R29LvMR5hyvGZlGJpmn65+A4xHXInJYiPuKzrKUnApeLZ+vw1HocOAZtWK0z3r26uA8kQYOKX9Qt/DbCdvsF9wF8gRK0ptx9M6R13NvBxvVQApfc9jB9nTzphOgM4JiEYvlV8FLhg9yZovMYd6Wwf3aoXK891VQxTr/kQYoq1Yp+68i6T4nNq7NWC+UNVjQHxNQMQMzU6lWCX8zyg3yH88OAQkUXIXKfQ+NkvYQ1cxaMoVPpY72+eVthKzpMeyHkBn7ciumk5qgLTEJAfWZpe4f4eFZj/Rc8Y8Jj2IS5kVPjUywQIDAQAB-----END PUBLIC KEY-----";
$rsa = new RSA();
$rsa->loadKey($publicRSAKey);
$rsa->setHash('sha256');
$plaintext = "My secret message.";
echo ($rsa->verify($plaintext, $signature) ? 'verified' : 'unverified');
}
with equal results. Does anyone have any clue why it fails? AFAIU I'm using the same algo in both C and PHP.
Any help appreciated.
You might also wonder why I'm trying to do this and why I don't validate separately in PHP using PHP functions and C functions in C. It's because I want to sign messages and files with A3 tokens accessible only from .so files in C. AFAIU PHP doesn't have any functions to sign files using A3 tokens.
If there is any option to sign files using A3 tokens from PHP, I'd really want to know.
For phpseclib do this before $rsa->verify():
$rsa->setSignatureMode(RSA::SIGNATURE_PKCS1);
To do this with X.509 certs...
$x509 = new \phpseclib\File\X509;
$x509->loadX509('...');
$rsa = $x509->getPublicKey();

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.

Using PHP/Python to verify ECDSA signature

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.

RSA Android Encrypt / RSA PHP Decrypt

i need some help for solve my problem.
Problem :
I want to encrypt a number (A) with public RSA Key from Android platform and then decrypt it on PHP Server with the private key.
On each platform, i can encrypt and decrypt data (it works well), but when the PHP script try to decrypt data encrypted from ANDROID, it doesn't work !!
Problem is not from HTTP Transmission, because I try to decrypt directly a generating Encryption from ANDROID (coded in Base64) and it not work at all ...
Findhere after my PHP Code for decrypt data :
class MyEncryption
{
public $privkey = '';
public $pubkey = '';
public function __construct(){
}
public function initialize() {
$fp=fopen("./encryption/asasap_public.pub","r");
$temp=fread($fp,8192);
fclose($fp);
$this->pubkey = openssl_pkey_get_public($temp);
$fp=fopen("./encryption/asasap.pem","r");
$temp=fread($fp,8192);
fclose($fp);
$this->privkey = openssl_get_privatekey($temp,'');
}
public function encrypt($data)
{
if (openssl_public_encrypt($data, $encrypted, $this->pubkey))
$data = base64_encode($encrypted);
else
throw new Exception('Unable to encrypt data. Perhaps it is bigger than the key size?');
return $data;
}
public function decrypt($data)
{
if (openssl_private_decrypt(base64_decode($data), $decrypted, $this->privkey))
$data = $decrypted;
else
$data = '';
return $data;
}
public function hex2bin($hexdata) {
$bindata = '';
for ($i = 0; $i < strlen($hexdata); $i += 2) {
$bindata .= chr(hexdec(substr($hexdata, $i, 2)));
}
return $bindata;
}
}
And i use this class like here :
$enc = new MyEncryption();
$enc->initialize();
$data_1 = 'K27booXr0zZK4BQlI45MIPJJjPPkpCCPELGvoK/wKYUwShIWE6szlZtrmV83C5eBIrT/3lxWTH3+IOA+5mefurVUvXmQIV7fXEHNHLphyM6L9gQsMAGZMCroPjWKvJM59OMS/d5dwwhiRgzVarxXSKpxBYhEYWJTu7nRJ+bZKjumeoqnCSpmntIiV+tRYgkYflOU6j2QlesjO5tzj/TL6n7vHSO/O1qafJkzHcv8Kn2hTy+IH7QXm7z5vtjXOucHkvBm1xWORXdifh+ChyVvP16dSEmCaCAH6KqtA4viX/HwRFEi4mIWaYSIQk74NdcnQOpFcTgEu2nDwtHaBMqahw==';
$data_2 = $enc->decrypt($data_1);
Here data_1 is initialized from the encrypt data (A=5) from android with the RSA Public Key (note : decrypt works well on Android), but after decryption in PHP, i get empty String ...
------------------------------------------ UPDATE -------
Please find here after the code for ANDROID part :
public byte[] encryptRSA(final InputStream publicKeyFile, String in) throws IOException, NoSuchAlgorithmException,
InvalidKeySpecException, InvalidKeyException, NoSuchPaddingException, IllegalBlockSizeException,
BadPaddingException {
byte[] encodedKey = new byte[5000];
publicKeyFile.read(encodedKey);
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(encodedKey);
KeyFactory kf = KeyFactory.getInstance("RSA");
PublicKey pkPublic = kf.generatePublic(publicKeySpec);
// Encrypt
Cipher pkCipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING");
pkCipher.init(Cipher.ENCRYPT_MODE, pkPublic);
return pkCipher.doFinal(in.getBytes());
}
After encrypt data, i convert the byte[] into Base64 (Base64.encodeToString(input, Base64.DEFAULT)).
For the certificate, i use RSA 2048 Bits convert into DER Format for Android.
------------------------------------------ SOLUTION -------
Error are in following Lines :
byte[] encodedKey = new byte[5000];
publicKeyFile.read(encodedKey);
We must read exactely the Public Key :
byte[] encodedKey = new byte[/*lenght of file*/];
publicKeyFile.read(encodedKey);
There are a lot of places this can go wrong:
You are passing 5000 bytes to X509EncodedKeySpec, most of which are 0. Are you sure you are getting the proper public key?
How long is the in String?
String.getBytes() uses the platform default encoding and may have unintended results. Use getBytes("ASCII") or getBytes("UTF-8").
Generally, you should just use SSL, and don't try to implement asymmetric encryption yourself.

Categories