AES encryption in PHP - AES decryption in GO - php

I am working on a legacy code written in PHP that I have to migrate to GO. We are required to store encrypted data, and decrypt on demand.
Because the legacy code will still have to run until everything is migrated to GO, I need to use the same encrypt / decrypt methods in GO too.
I have been strugling with this issue for the last 10 hours. I have tried (I think) all the Stackoverflow suggestions + many others.
The servers are running OpenSSL 1.1.1a. I have found and tested something helpful, but without success:
https://dequeue.blogspot.com/2014/11/decrypting-something-encrypted-with.html
I do not have to much knowledge about encryption in general, but I can understand it's basics.
So, if there is anyone kind enough to give me some suggestions ... please.
PHP legacy code
var $encryption_key = 'XXX';
var $cipher = 'aes-256-cbc';
function encrypt($text) {
global $encryption_key, $cipher;
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($cipher));
$data = openssl_encrypt($text, $cipher, $encryption_key, OPENSSL_RAW_DATA, $iv);
return base64_encode($iv . $data);
}
function decrypt($text) {
global $encryption_key, $cipher;
$data = base64_decode($text);
$iv_len = openssl_cipher_iv_length($cipher);
$iv = substr($data, 0, $iv_len);
$data = substr($data, $iv_len);
return openssl_decrypt($data, $cipher, $encryption_key, OPENSSL_RAW_DATA, $iv);
}
Last code tested in GO for decrypting data (ignore the block below and scroll for updated code)
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/md5"
"encoding/base64"
"fmt"
)
func main(){
result, _ := DecryptString(`password`, `U2FsdGVkX1+ywYxveBnekSnx6ZP25nyPsWHS3oqcuTo=`)
fmt.Printf("Decrypted string is: %s", result)
}
var openSSLSaltHeader string = "Salted_" // OpenSSL salt is always this string + 8 bytes of actual salt
type OpenSSLCreds struct {
key []byte
iv []byte
}
// Decrypt string that was encrypted using OpenSSL and AES-256-CBC
func DecryptString(passphrase, encryptedBase64String string) ([]byte, error) {
data, err := base64.StdEncoding.DecodeString(encryptedBase64String)
if err != nil {
return nil, err
}
saltHeader := data[:aes.BlockSize]
if string(saltHeader[:7]) != openSSLSaltHeader {
return nil, fmt.Errorf("Does not appear to have been encrypted with OpenSSL, salt header missing.")
}
salt := saltHeader[8:]
creds, err := extractOpenSSLCreds([]byte(passphrase), salt)
if err != nil {
return nil, err
}
return decrypt(creds.key, creds.iv, data)
}
func decrypt(key, iv, data []byte) ([]byte, error) {
if len(data) == 0 || len(data)%aes.BlockSize != 0 {
return nil, fmt.Errorf("bad blocksize(%v), aes.BlockSize = %v\n", len(data), aes.BlockSize)
}
c, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
cbc := cipher.NewCBCDecrypter(c, iv)
cbc.CryptBlocks(data[aes.BlockSize:], data[aes.BlockSize:])
out, err := pkcs7Unpad(data[aes.BlockSize:], aes.BlockSize)
if out == nil {
return nil, err
}
return out, nil
}
// openSSLEvpBytesToKey follows the OpenSSL (undocumented?) convention for extracting the key and IV from passphrase.
// It uses the EVP_BytesToKey() method which is basically:
// D_i = HASH^count(D_(i-1) || password || salt) where || denotes concatentaion, until there are sufficient bytes available
// 48 bytes since we're expecting to handle AES-256, 32bytes for a key and 16bytes for the IV
func extractOpenSSLCreds(password, salt []byte) (OpenSSLCreds, error) {
m := make([]byte, 48)
prev := []byte{}
for i := 0; i < 3; i++ {
prev = hash(prev, password, salt)
copy(m[i*16:], prev)
}
return OpenSSLCreds{key: m[:32], iv: m[32:]}, nil
}
func hash(prev, password, salt []byte) []byte {
a := make([]byte, len(prev)+len(password)+len(salt))
copy(a, prev)
copy(a[len(prev):], password)
copy(a[len(prev)+len(password):], salt)
return md5sum(a)
}
func md5sum(data []byte) []byte {
h := md5.New()
h.Write(data)
return h.Sum(nil)
}
// pkcs7Unpad returns slice of the original data without padding.
func pkcs7Unpad(data []byte, blocklen int) ([]byte, error) {
if blocklen <= 0 {
return nil, fmt.Errorf("invalid blocklen %d", blocklen)
}
if len(data)%blocklen != 0 || len(data) == 0 {
return nil, fmt.Errorf("invalid data len %d", len(data))
}
padlen := int(data[len(data)-1])
if padlen > blocklen || padlen == 0 {
return nil, fmt.Errorf("invalid padding")
}
pad := data[len(data)-padlen:]
for i := 0; i < padlen; i++ {
if pad[i] != byte(padlen) {
return nil, fmt.Errorf("invalid padding")
}
}
return data[:len(data)-padlen], nil
}
The code written in GO should be able to decrypt data encrypted in PHP. The only result that I get is an error: Error: Does not appear to have been encrypted with OpenSSL, salt header missing.
UPDATE: Go code updated
The code below almost works. IV, key, cipher binary text are all the same as in PHP, but the final result is still encrypted (or wrongly decrypted)
package main
import (
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"fmt"
)
func main() {
var stringToDecode string = "base64_encode(SOME_PHP_ENCRYPTED_USING_THE_PHP_CODE_ABOVE)"
var cipherKey = []byte("myprivatekey")
content, err := base64.StdEncoding.DecodeString(stringToDecode)
if err != nil {
fmt.Printf("Error: %s", err)
}
fmt.Println("Cipher key: ", string(cipherKey))
fmt.Println("Cipher key length: ", len(cipherKey))
cipherText := content
cipherBlock, err := aes.NewCipher(cipherKey)
if err != nil {
panic(err)
}
iv := cipherText[:aes.BlockSize]
fmt.Println("iv:", base64.StdEncoding.EncodeToString(iv))
fmt.Println("Cipher text:", string(cipherText[aes.BlockSize:]))
cipherText = cipherText[aes.BlockSize:]
fmt.Println("Cipher text binary: ", string(cipherText))
if len(cipherText)%aes.BlockSize != 0 {
panic(fmt.Sprintf("Cipher text (len=%d) is not a multiple of the block size (%d)", len(cipherText), aes.BlockSize))
}
mode := cipher.NewCBCDecrypter(cipherBlock, iv)
mode.CryptBlocks(cipherText, cipherText)
// The output is not decrypted as expected
fmt.Printf("The result: %s\n", string(cipherText))
}

Related

openssl_sign with OPENSSL_ALGO_SHA1 algorithm in golang

I have some php code like this
$signature = '';
$data = strval($aMessage);
if (!openssl_sign($data, $signature, $key, OPENSSL_ALGO_SHA1)) {
return null;
}
$signature = base64_encode($signature);
I make a plan to move it into golang. so I have the code like this
var rpk *rsa.PrivateKey
var bs []byte
if rpk, err = c.getRSAPrivateKey(); err != nil {
return
}
if bs, err = json.Marshal(c); err != nil {
return
}
var hash = crypto.SHA1.New()
hash.Write(bs)
if bs, err = rsa.SignPKCS1v15(rand.Reader, rpk, crypto.SHA1, hash.Sum(nil)); err != nil {
return
}
return base64.RawURLEncoding.EncodeToString(bs), err
when bs have a small length it works well and the result is the same as php code, but it works bad
when bs has a big length. where is my wrong?
I hope the result is always the same
Updated:
the problem is. golang base64encoding , I hav solved with below codes
var b64s = base64.URLEncoding.EncodeToString(bs)
b64s = strings.ReplaceAll(b64s, "-", "+")
b64s = strings.ReplaceAll(b64s, "_", "/")

compare AES-256-CBC hash in golang decrypt

I'm trying to compare the hash of a password, but when I compare it I get hieroglyphs and can't match whether it's true or false.
analog php function:
/*
* Split hash into pieces
* ([0] = ??, [1] = master key, [2] = salt len, [3] = salt, [4] = iteration count, [5] = salt position, [6] = ??, [7] == ??, [8] == ??)
*/
$passHashArray = explode('$', $passHash);
/*
* Combine passphrase and salt
*/
$passToHash = $testPassphrase.hex2bin($passHashArray[3]);
/*
* Hash $passToHash $passHasArray[4] times with SHA512
*/
for($i = 0; $i < $passHashArray[4]; $i++){
$passToHash = hash('SHA512', $passToHash, true);
}
/*
* Get Key and Iv from $passToHash for final encryption
*/
$key = substr($passToHash, 0, 32);
$iv = substr($passToHash, 32, 16);
/*
* final passphrase encryption
*/
if(in_array('aes-256-cbc', openssl_get_cipher_methods())){
if(openssl_decrypt(hex2bin($passHashArray[1]), 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv)){
echo 'password correct';
}else{
echo 'decrypt failed';
}
}
go function:
var passwordHash = "64$718eadbd49dbee69e2b3e5f9659c361129cc07199d421d01892694477331ad8a$16$dce01545e0c918e7$76012$2$00$2$00"
var password = "12345678910"
func main() {
var passwordHashArray = strings.Split(passwordHash, "$")
/*
* Convert to hex to bin passphrase and salt
*/
hex2Bin, err := hex.DecodeString(passwordHashArray[3])
if err != nil {
log.Printf("error hex decode string password hash array: %s", err)
}
/*
* Combine passphrase and salt
*/
passwordToHash := strings.Join([]string{ password, string(hex2Bin)}, "")
/*
* Hash $passToHash $passHasArray[4] times with SHA512
*/
intVar, err := strconv.Atoi(passwordHashArray[4])
if err != nil {
log.Printf("error password hash array string to int: %s", err)
}
passwordToHashBinary := make([]byte, 32)
passwordToHashBinary = hashSHA512([]byte(passwordToHash))
for i := 1; i < intVar; i++ {
passwordToHashBinary = hashSHA512(passwordToHashBinary)
}
/*
* Get Key and Iv from $passToHash for final encryption
*/
var encKeyDecoded = make([]byte, 32)
copy(encKeyDecoded, passwordToHashBinary[:32])
var ivDecoded = make([]byte, 16)
copy(ivDecoded, passwordToHashBinary[32:48])
cipherTextDecoded, err := hex.DecodeString(passwordHashArray[1])
if err != nil {
log.Printf("error hex decode string password hash array: %s", err)
}
results, err := decrypt(cipherTextDecoded, encKeyDecoded, ivDecoded)
if err != nil {
log.Printf("error result decode password: %s", err)
}
log.Printf("%s", string(results))
log.Printf("%x", string(results))
}
func decrypt(cipherTextDecoded []byte, encKeyDecoded []byte, ivDecoded []byte) ([]byte, error) {
block, err := aes.NewCipher(encKeyDecoded)
if err != nil {
return nil, err
}
if len(cipherTextDecoded) < aes.BlockSize {
return nil, fmt.Errorf("ciphertext too short")
}
if len(cipherTextDecoded)%aes.BlockSize != 0 {
return nil, fmt.Errorf("ciphertext is not a multiple of the block size")
}
mode := cipher.NewCBCDecrypter(block, ivDecoded)
mode.CryptBlocks(cipherTextDecoded, cipherTextDecoded)
return cipherTextDecoded, nil
}
func hashSHA512(crypto []byte) []byte {
hash := sha512.New()
hash.Write(crypto)
sha := hash.Sum(nil)
return sha
}
it is worth noting that in php the password is displayed correctly, but on the go I get a line like:
���Pʎ&L�t→]��f�►►►►►►►►►►►►►►►►
First of all, I don't understand where it comes from:
►►►►►►►►►►►►►►►►
How can I check if a password is valid in golang?
if () {good} else {bad}
out php:
https://onecompiler.com/php/3xqvgkhbr
out go:
https://go.dev/play/p/HUxoD29fM4c
i never tried using AES on my site to store password but here's how i do it i'm using PDO prepared statement and bcrypt
$read_username = $pdo->prepare("SELECT * FROM users WHERE username = :username LIMIT 1");
$read_username->execute([':username' => $username]);
if ($read_username->rowCount() > === 1) {
$row = $write_account->fetch(PDO::FETCH_ASSOC);
$read_username = null; // close connection we already got what we need
$pdo = null; // close connection we already got what we need
$stored_hash = $row['password']; // bind the hash stored on db as $stored_hash
if (password_verify($password, $stored_hash)) { // compare user input to $stored_hash
$_SESSION['username'] = $username . bin2hex(random_bytes(12));
header('location: index.php');
die("ACCESS GRANTED!");
} else {
array_push($errors, "Incorrect password!");
}
} else {
array_push($errors, "Account does not exist!");
}
also your if else concern is easy it goes like this
$hotdog = 123;
if ($hotdog == 123) {
echo "hotdog";
} else {
echo "not hotdog";
}

How to read pkcs12 content in golang, i have example in PHP

There is a decryption and signature interface. I want to move from PHP to Golang. The PHP function is as follows:
function getSignature($param){
if (is_string($param)) {
$file_private = 'file.p12';
if (!$cert_store = file_get_contents($file_private)) {
return "Error: Unable to read the cert file\n";
}
$signature = "";
$algo = "sha256WithRSAEncryption";
$password = "PASSWORD";
$private_key_file = openssl_pkcs12_read($cert_store, $cert_info, $password);
if ($private_key_file)
{
$private_key = $cert_info['pkey'];
openssl_sign($param, $signature, $private_key, $algo);
return htmlentities(base64_encode($signature));
}
}
return false;
}
I want to use golang to achieve.
How can I convert into golang?
SOLVED
This is what actually my code in golang:
func Sign(privateKey *rsa.PrivateKey, data string) (string, error) {
h := crypto.SHA256.New()
h.Write([]byte(data))
hashed := h.Sum(nil)
sign, err := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA256, hashed)
if err != nil {
return "", err
}
return base64.RawURLEncoding.EncodeToString(sign), err
}
func read_keys() {
b, err := ioutil.ReadFile("file.p12")
if err != nil {
fmt.Println(err)
}
password := "PASSWORD"
privk, _, err := pkcs12.Decode(b, password)
if err != nil {
fmt.Println(err)
}
pv := privk.(*rsa.PrivateKey)
sign, _ := Sign(pv, "Your String Data")
fmt.Print(sign)
}
this is the package you're looking for
data, err := ioutil.ReadFile(*in)
if err != nil {
log.Fatal(err)
}
privateKey, certificate, err := pkcs12.Decode(data, *password)
if err != nil {
log.Fatal(err)
}
pv := privateKey.(*rsa.PrivateKey)
signature, err := rsa.SignPKCS1v15(rand.Reader, privateKey, rypto.SHA256, hash)
if err != nil {
log.Fatal(err)
}

AES encryption with Go and PHP

I am using AES encryption in Go and PHP. But both the languages does not encrypt/decrypt each other ciphertext. Following i have tried in php
class Crypto {
private $encryptKey = "keyforencryption";
private $iv = 'ivusedforencrypt';
private $blocksize = 16;
public function encrypt($toEncrypt){
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CFB);
//$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
return base64_encode($this->iv . mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $this->encryptKey, $toEncrypt, MCRYPT_MODE_CFB, $this->iv));
}
public function decrypt($toDecrypt){
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CFB);//$this->blocksize;
$toDecrypt = base64_decode($toDecrypt);
return rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $this->encryptKey, substr($toDecrypt, $iv_size), MCRYPT_MODE_CFB, substr($toDecrypt, 0, $iv_size)));
}
}
$c = new Crypto();
echo "Encrypted : ".$e = $c->encrypt("test");
echo "<br/>Decrypted : ".$c->decrypt($e);
output : aXZ1c2VkZm9yZW5jcnlwdDpdZEinU2rB
and this one in Go with AES
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/base64"
"errors"
"fmt"
"io"
"log"
)
func main() {
key := []byte("keyforencryption")
plaintext := []byte("test")
fmt.Printf("%s\n", plaintext)
ciphertext, err := encrypt(key, plaintext)
if err != nil {
log.Fatal(err)
}
b := base64.StdEncoding.EncodeToString(ciphertext)
fmt.Printf("Encrypted text : %s\n", b)
result, err := decrypt(key, b)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Decrypted Text : %s\n", result)
}
func encrypt(key, text []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
//b := base64.StdEncoding.EncodeToString(text)
ciphertext := make([]byte, aes.BlockSize+len(text))
iv := ciphertext[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return nil, err
}
cfb := cipher.NewCFBEncrypter(block, iv)
cfb.XORKeyStream(ciphertext[aes.BlockSize:], []byte(text))
return ciphertext, nil
}
func decrypt(key []byte, text1 string) ([]byte, error) {
text, _ := base64.StdEncoding.DecodeString(string(text1))
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
if len(text) < aes.BlockSize {
return nil, errors.New("ciphertext too short")
}
iv := text[:aes.BlockSize]
text = text[aes.BlockSize:]
cfb := cipher.NewCFBDecrypter(block, iv)
cfb.XORKeyStream(text, text)
b := base64.StdEncoding.EncodeToString(text)
data, err := base64.StdEncoding.DecodeString(string(b))
if err != nil {
return nil, err
}
return data, nil
}
output : ZVnhCXjIvtGKBdqvjwHRZKcVy34=
any help would be appreciable.
CFB mode has an issue, this will work in CBC mode
class Crypto {
private $encryptKey = "keyforencryption";
public function encrypt($toEncrypt){
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
return base64_encode($iv . mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $this->encryptKey, $toEncrypt, MCRYPT_MODE_CBC, $iv));
}
public function decrypt($toDecrypt){
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
echo "<br/>".$toDecrypt = base64_decode($toDecrypt);
return rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $this->encryptKey, substr($toDecrypt, $iv_size), MCRYPT_MODE_CBC, substr($toDecrypt, 0, $iv_size)));
}
}
$c = new Crypto();
echo "Encrypted : ".$e = $c->encrypt("test123");
echo "<br/>Decrypted : ".$c->decrypt($e);
and this one in golang
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/base64"
"fmt"
"io"
"bytes"
)
func main() {
e:= cbcEncrypt()
fmt.Printf("Encrypted String : %s\n", e)
d:= cbcDecrypt(e)
fmt.Printf("Decrypted String : %s\n", d)
}
func cbcDecrypt(text1 string) []byte{
key := []byte("keyforencryption")
ciphertext, _ := base64.StdEncoding.DecodeString(string(text1))
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
// include it at the beginning of the ciphertext.
if len(ciphertext) < aes.BlockSize {
panic("ciphertext too short")
}
iv := ciphertext[:aes.BlockSize]
ciphertext = ciphertext[aes.BlockSize:]
// CBC mode always works in whole blocks.
if len(ciphertext)%aes.BlockSize != 0 {
panic("ciphertext is not a multiple of the block size")
}
mode := cipher.NewCBCDecrypter(block, iv)
// CryptBlocks can work in-place if the two arguments are the same.
mode.CryptBlocks(ciphertext, ciphertext)
ciphertext = PKCS5UnPadding(ciphertext)
return ciphertext
}
func cbcEncrypt() string{
key := []byte("keyforencryption")
plaintext := []byte("testssssss")
plaintext = PKCS5Padding(plaintext, 16)
// CBC mode works on blocks so plaintexts may need to be padded to the
// next whole block. For an example of such padding, see
// https://tools.ietf.org/html/rfc5246#section-6.2.3.2. Here we'll
// assume that the plaintext is already of the correct length.
if len(plaintext)%aes.BlockSize != 0 {
panic("plaintext is not a multiple of the block size")
}
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
// The IV needs to be unique, but not secure. Therefore it's common to
// include it at the beginning of the ciphertext.
ciphertext := make([]byte, aes.BlockSize+len(plaintext))
iv := ciphertext[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(ciphertext[aes.BlockSize:], plaintext)
// It's important to remember that ciphertexts must be authenticated
// (i.e. by using crypto/hmac) as well as being encrypted in order to
// be secure.
return base64.StdEncoding.EncodeToString(ciphertext)
}
func PKCS5Padding(src []byte, blockSize int) []byte {
padding := blockSize - len(src)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(src, padtext...)
}
func PKCS5UnPadding(src []byte) []byte {
length := len(src)
unpadding := int(src[length-1])
return src[:(length - unpadding)]
}
this should work
Also use padding for encoding and unpadding for decode in php.
function pkcs5_pad($text)
{
$blocksize = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$pad = $blocksize - (strlen($text) % $blocksize);
return $text . str_repeat(chr($pad), $pad);
}
function pkcs5_unpad($text)
{
$block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$pad = ord($text[($len = strlen($text)) - 1]);
$len = strlen($text);
$pad = ord($text[$len-1]);
return substr($text, 0, strlen($text) - $pad);
}

sign a file with openssl in php and verify in c++

I wrote a webservice that server is written in php and client is written in c++, and I used openssl package for generating rsa pair key to secure data transferming.
At the first I wrote both client an server in php for preparing services and every things goes OK. but when I started transfer client php code into c++ I face into problems with openssl methods.
The big problem is that the signed data does not match in both php and c++ codes.
I get md5 of data and use openssl_sign method for signing md5 data and then append the sign at the end of plain data and send to client (In the past public key have been sent for client). in the client I did this progress again. but the sign dos not verify correctly.
What is wrong in may program?
please help, thanks.
php side (webservice) code:
function sign($cleartext)
$msg_hash = md5($cleartext);
$sig = "";
$ok = openssl_sign($msg_hash, $sig, $this->private_key);
if ($ok == 1)
{
$signed_data = $cleartext . "----SIGNATURE:----" . base64_encode($sig);
//$signed_data = $this->encryptAES($signed_data, $this->password);
return base64_encode(mysql_real_escape_string($signed_data));
}
elseif ($ok == 0)
{
$eroor = "bad";
return base64_encode($eroor);
}
else
{
$eroor = "ugly, error checking signature";
return base64_encode($eroor);
}
}
and C++ side (client) Code:
int Crypto::rsaVerify(string msgStr, const char *pk) {
int length;
char *pkStr = new char[this->publicKey.length() + 1];
strcpy_s(pkStr, this->publicKey.length()+1,this->publicKey.c_str());
this->setPubKey((unsigned char *)pkStr,strlen(pkStr));
// Find and Splite Data
size_t current = 0;
string delimiters = "----SIGNATURE:----";
size_t next = msgStr.find( delimiters, current );
string dataStr = msgStr.substr( current, next - current );
char *msg = new char[dataStr.length() + 1];
strcpy_s(msg, dataStr.length()+1,dataStr.c_str());
// Find and Split sign
string signData = msgStr.substr(next + delimiters.length(), msgStr.length());
Coding *codingObj = new Coding();
signData = codingObj->base64_decode(signData);
char *signBuf = new char[signData.length() + 1];
strcpy_s(signBuf, signData.length()+1, signData.c_str());
unsigned char *dataMD5 = new unsigned char [MD5_DIGEST_LENGTH];
MD5((const unsigned char *)msg,strlen(msg),dataMD5);
char md5String[MD5_DIGEST_LENGTH + 1];
AsciiString2HexString(dataMD5,(unsigned char *)md5String, MD5_DIGEST_LENGTH);
md5String[MD5_DIGEST_LENGTH] = '\0';
char md5String1[MD5_DIGEST_LENGTH + 1];
AsciiString2HexString((unsigned char *)md5String1,(unsigned char *)md5String1, MD5_DIGEST_LENGTH);
md5String1[MD5_DIGEST_LENGTH] = '\0';
unsigned char * key2;
getPubKey(&key2);
unsigned int signLen = 256;//strlen(md5String);
char errorBuffer[120];
unsigned char message_digest[SHA_DIGEST_LENGTH];
SHA1((const unsigned char *)md5String1, strlen(md5String1), message_digest);
if(RSA_verify(NID_sha1,(const unsigned char *)message_digest, SHA_DIGEST_LENGTH,(const unsigned char *)signBuf,signLen,this->keyPair))
{
return 1;
}
else
{
ERR_error_string(ERR_get_error(), errorBuffer);
}
if(RSA_verify(NID_sha1,(const unsigned char *)md5String1, strlen(md5String1),(const unsigned char *)signBuf,signLen,this->keyPair))
{
return 1;
}
else
{
ERR_error_string(ERR_get_error(), errorBuffer);
}
if(RSA_verify(NID_sha1,(const unsigned char *)md5String, strlen(md5String),(const unsigned char *)signBuf,signLen,this->keyPair))
{
return 1;
}
else
{
ERR_error_string(ERR_get_error(), errorBuffer);
}
if(RSA_verify(NID_sha1,(const unsigned char *)dataMD5, strlen((char *)dataMD5),(const unsigned char *)signBuf,signLen,this->keyPair))
{
return 1;
}
else
{
ERR_error_string(ERR_get_error(), errorBuffer);
}
return 0;
}
int Crypto::getPriKey(unsigned char **priKey) {
BIO *bio = BIO_new(BIO_s_mem());
PEM_write_bio_RSAPrivateKey(bio, this->keyPair, NULL, NULL, NULL, NULL, NULL);
int priKeyLen = BIO_pending(bio);
*priKey = (unsigned char*)malloc(priKeyLen);
if(priKey == NULL) return FAILURE;
BIO_read(bio, *priKey, priKeyLen);
// Insert the NUL terminator
(*priKey)[priKeyLen-1] = '\0';
BIO_free_all(bio);
return priKeyLen;
}
Maybe because openssl_sign need data as first argument and not the hash of data. By default, the hash is caclulated by this function with OPENSSL_ALGO_SHA1.
And, if you can, prefere SHA2, 256bits and more. MD5 and SHA1 are not recommended for new projects...

Categories