enter image description hereI want to encrypted JPG file in Java with AES, but I don't know how to decrypt the JPG file in javascript. Anyone has better idea?
this is my java code。
`private static void EncFile(File srcFile, File encFile) throws Exception
{
if(!srcFile.exists()){
System.out.println("source file not exixt");
return;
}//
if(!encFile.exists()){
System.out.println("encrypt file created");
encFile.createNewFile();
}
byte[] bytes = new byte[1024*8];
String key = "1234567812345678";
String iv = "1234567812345678";
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
int blockSize = cipher.getBlockSize();
SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
InputStream fis = new FileInputStream(srcFile);
// CipherInputStream cin = new CipherInputStream(fis, cipher);
OutputStream fos = new FileOutputStream(encFile);
while ((dataOfFile = fis.read(bytes)) >0) {
byte[] encrypted = cipher.doFinal(bytes);
fos.write(encrypted,0,dataOfFile);
}
fis.close();
fos.flush();
fos.close();
}`
this my javascipt code, I have used CryptoJS and Decrypt does
var key = CryptoJS.enc.Latin1.parse('1234567812345678');
var iv = CryptoJS.enc.Latin1.parse('1234567812345678');
var url = "http://192.168.0.103/show3d_test/test/CR4/E1234.png";
var xhr = new XMLHttpRequest();
xhr.open("GET",url,true);
xhr.responseType = "arraybuffer";
xhr.onload = function() {
if(xhr.readyState ==4){
if (xhr.status == 200){
process(xhr.response,key);
}
}
}
xhr.send();
function process(buffer,key) {
var view = new Uint8Array(buffer);
var contentWA = CryptoJS.enc.u8array.parse(view);
var dcBase64String = contentWA.toString(CryptoJS.enc.Base64);
var decrypted = CryptoJS.AES.decrypt(dcBase64String,key,
{iv:iv,mode:CryptoJS.mode.CBC,padding:CryptoJS.pad.NoPadding});
var d64 = decrypted.toString(CryptoJS.enc.Base64);
var img = new Image;
img.src = "data:image/png;base64,"+d64;
document.body.append(img);
} `
Anyone know how to do that? I've seen so much example about CryptoJS - Java encrypt/decrypt but most of them use hardcoded IV/key, or just send IV/key from cryptoJS side to Java side. All I have is a passphrase, just like what this site do!
Not sure what the exact question is but this should help.
A general and secure method for an IV is to create one with a CSPRNG (random bytes) and prefix the encrypted data with the IV so it will be available for decryption. The IV does not need to be secret.
When using "AES/CBC/NoPadding" the input must be an exact multiple of the block size (16-bytes for AES). Generally PKCS#7 (PKCS#5) padding is specified so there are no limits on the data length to be encrypted.
Related
I'm trying to reproduce the following code in javascript
var hashInput = "a::string::to::hash";
var privateKey = "C0B615950F9D577A4EAF64C9B4F2E50F3DA2C6BB6F790FA346E9732788B29A08AC5444F1B82984DB190A75D3861CC4802D598EBF0025FD1C327928F43EB1C80E";
byte[] inputBytes = Encoding.UTF8.GetBytes(hashInput);
byte[] keyBytes = Encoding.UTF8.GetBytes(privateKey);
HMACSHA256 hmac = new HMACSHA256(keyBytes);
hmac.Initialize();
var clientHash = hmac.ComputeHash(inputBytes);
var base64 = Convert.ToBase64String(clientHash);
But i ignore how can i import Enocde and HMACSHA256. I found the code in the following answer:
stackoverflow answer
This is what i've tried so far
const HashMAC = (key, message) => {
let keyBytes = Buffer.from(key, 'base64');
let messageBytes = Buffer.from(message, 'utf8');
// i don't know which library should i use, in crypto js thay're talking about
message and key noy bytes i tried but nothing.
const base64 = Buffer.from(hmac, 'base64');
return base64;
};
I want to create a HMAC256 key from a string with a HMAC key based on my C# project in Javascript. however, each project has different results and can't seem to find a way to make the results identical.
C# PROJECT
private string CalculateHMAC(string hmacKey, string signingstring) {
byte[] key = PackH(hmacKey) //returns 32 bit array;
byte[] data = Encoding.UTF8.GetBytes(signingstring);
try {
using(HMACSHA256 hmac = new HMACSHA256(key)) {
// Compute the hmac on input data bytes
byte[] rawHmac = hmac.ComputeHash(data);
// Base64-encode the hmac
return Convert.ToBase64String(rawHmac);
}
} catch (Exception e) {
throw new Exception("Failed to generate HMAC : " + e.Message);
}
}
JAVASCRIPT CODE
var hash = CryptoJS.HmacSHA256(byteString, hmacKeyinString);
var msg = hash.toString(CryptoJS.enc.Base64);
Thank you in advance.
Using CryptoJS in my javascript project
fixed with this line of code
var wordsKey = CryptoJS.enc.Hex.parse('yourkey');
var hash = CryptoJS.HmacSHA256(convertString, wordsKey);
var hashInBase64 = CryptoJS.enc.Base64.stringify(hash);
In Java to make a signature of some data we are using Mac instance which allows to sign any byte array. How to make a function in JavaScript which produces the same signature for the same byte array?
An example of Java implementation (method sign signs message with HmacSHA256 and than converts signature into url-safe base64 string):
public static void main(String[] args) throws InvalidKeyException, NoSuchAlgorithmException {
byte[] secret = new byte[5];
secret[0] = 0x1e;
secret[1] = 0x03;
secret[2] = 0x01;
secret[3] = 0x02;
secret[4] = 0x03;
byte[] message = new byte[5];
message[0] = 0x01;
message[1] = 0x03;
message[2] = 0x02;
message[3] = 0x1e;
message[4] = 0x03;
System.out.println(sign(secret, message));
}
private static String sign(byte[] secret, byte[] message) throws NoSuchAlgorithmException, InvalidKeyException {
Mac sha256Hmac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKey = new SecretKeySpec(secret, "HmacSHA256");
sha256Hmac.init(secretKey);
byte[] signature = sha256Hmac.doFinal(message);
return Base64.getUrlEncoder().withoutPadding().encodeToString(signature);
}
The example above produces q-l6FioFNkAqMIIxX5rs3AF-VnGIzpApCSSDHmnmjF8 signature string. I am trying to create the equivalent of sign method in JavaScript to get the same signature.
function main(){
var secret = [5];
secret[0] = 0x1e;
secret[1] = 0x03;
secret[2] = 0x01;
secret[3] = 0x02;
secret[4] = 0x03;
var message = [5];
message[0] = 0x01;
message[1] = 0x03;
message[2] = 0x02;
message[3] = 0x1e;
message[4] = 0x03;
console.log(sign(secret, message));
}
function sign(secret, message){
// ?
}
I couldn't find a way to sign bytes with CryptoJS.
The solution appeared to be not complicated. Before using CryptoJS we have to correctly convert bytes array into a String. After returning base64 string we should escape it to url friendly string.
function sign(secret, message){
var secretString = String.fromCharCode.apply(String, secret);
var messageString = String.fromCharCode.apply(String, message);
var hash = CryptoJS.HmacSHA256(messageString, secretString);
return CryptoJS.enc.Base64.stringify(hash).replace(/\+/g, '-').replace(/\//g, '_').replace(/\=+$/, '');
}
Base64 and HmacSHA256 should be included in CryptoJS after install. Try this approach:
function sign(secret, message){
const hash = CryptoJS.HmacSHA256(message.join(''), secret.join(''));
const hashInBase64 = CryptoJS.enc.Base64.stringify(hash);
return hashInBase64}
I am getting corrupted image icon while displaying b64 encoded png image response from rest API.
javascript-
function getcap(){
var http = new XMLHttpRequest()
http.open("GET", "http://localhost:8888/newcaptcha",true)
http.setRequestHeader("Content-Type", "text/plain;charset=UTF-8");
http.setRequestHeader("Access-Control-Allow-Origin", "http://localhost:8888");
http.send()
http.onload = () => {
var resp=unescape(encodeURIComponent(http.responseText));
var b64Response = window.btoa(resp);
console.log('data:image/png;base64,'+b64Response);
document.getElementById("capimg").src = 'data:image/png;base64,'+b64Response;
}
}
html -
<div id="newCaptcha" onClick="getcap()" ><h5>new captcha:</h5><img id="capimg" width="30" height ="30"/></div>
b64 encoded response-
server code -
#CrossOrigin(origins = "http://localhost:8080")
#RequestMapping(value = "/newcaptcha", method = RequestMethod.GET, produces = "image/png")
public #ResponseBody byte[] getnewCaptcha() {
try {
Random random = new Random();
imgkey= random.nextInt(3);
InputStream is = this.getClass().getResourceAsStream("/"+captcheMap.get(imgkey)+".png");
BufferedImage img = ImageIO.read(is);
ByteArrayOutputStream bao = new ByteArrayOutputStream();
ImageIO.write(img, "png", bao);
return bao.toByteArray();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
The base 64 response attached doesn't seem to actually load the image, if I open it in browser.
Secondly, I can see that that one problem that can cause this is reloading of DOM element img, if its not handled by any framework, you may have to manually intervene. To check this, you can test using a local image and load that. If it doesn't work, then you got your root cause. And if it does, then this base64 response is an issue.
Also, check the console for any errors and do update here.
As I pointed out in comments, probably you don't need b64. However, if you really want, read this.
There are tons on questions on Stackoverflow on this subject, and few answers. I have put together all pieces.
The point is that btoa() badly supports binary data.
Here: convert binary data to base-64 javaScript you find the suggestion to use arraybuffers as responseType, instead of just text.
Here: ArrayBuffer to base64 encoded string you find a function that converts arraybuffers to b64.
Putting all togheter:
function getcap(){
var http = new XMLHttpRequest();
http.open("GET", "/newcaptcha",true);
http.responseType = 'arraybuffer';
http.send();
http.onload = () => {
console.log(http.response);
var b64Response = _arrayBufferToBase64(http.response);
document.getElementById("capimg").src = 'data:image/png;base64,'+b64Response;
}
}
function _arrayBufferToBase64( buffer ) {
var binary = '';
var bytes = new Uint8Array( buffer );
var len = bytes.byteLength;
for (var i = 0; i < len; i++) {
binary += String.fromCharCode( bytes[ i ] );
}
return window.btoa( binary );
}
I am creating a public/private key on the server, sending the key to the JavaScript client where it encrypts a users password. The client sends the password to the server, and the server uses the private key to decrypt it, but the password is coming back null. I have verified all values supporting the situation are correct, so it's something with the encryption/decryption specifically. Where am I going wrong?
Possibly, is cryptico.js not compatible with php openssl?
Library Info:
https://github.com/wwwtyro/cryptico
http://www.php.net/manual/en/function.openssl-pkey-new.php
Here are relevant code snippets:
PHP - create public/private key
$config = array(
"digest_alg" => "sha512",
"private_key_bits" => 2048,
"private_key_type" => OPENSSL_KEYTYPE_RSA,
);
// Create the private and public key
$res = openssl_pkey_new($config);
// Extract the private key from $res to $privateKey
openssl_pkey_export($res, $privateKey);
// Extract the public key from $res to $publicKey
$publicKey = openssl_pkey_get_details($res);
$publicKey = $publicKey["key"];
JavaScript - Client encrypts data with public key.
var xhr = new XMLHttpRequest();
var data = new FormData();
xhr.open('POST', '/signUp2.php');
data.append('user', User);
var encryptedPassword = cryptico.encrypt(password, localStorage["publicKey"]);
data.append('password', encryptedPassword.cipher);
xhr.onreadystatechange = function()
{
if(xhr.readyState == 4 && xhr.status == 200)
{
var jsonArray = JSON.parse(xhr.responseText);
if(jsonArray[0] == "0")
{
alert("Account created. You may now sign in.");
}
else
alert("Error Code: " + jsonArray[0]);
}
}
xhr.send(data);
PHP - Server recieves encrypted password and attemps to decrypt unsuccessfully
openssl_private_decrypt($encryptedPassword, $decryptedPassword, $row[1]);
cryptico.js could work with openssl, but we have to modify it a bit.
it don't directly recognize the public key in pem format (which openssl use). we have to extract the 'n' and 'e' part of a public key in php side:
$key = openssl_pkey_new(array(
'private_key_bits' => 1024,
'private_key_type' => OPENSSL_KEYTYPE_RSA,
'digest_alg' => 'sha256'
));
$detail = openssl_pkey_get_details($key);
$n = base64_encode($detail['rsa']['n']);
$e = bin2hex($detail['rsa']['e']);
also, cryptico.js hardcoded the 'e' part of a public key (see definition of publicKeyFromString in api.js), so we need to fix this:
my.publicKeyFromString = function(string)
{
var tokens = string.split("|");
var N = my.b64to16(tokens[0]);
var E = tokens.length > 1 ? tokens[1] : "03";
var rsa = new RSAKey();
rsa.setPublic(N, E);
return rsa
}
now we are able to encrypt strings:
var publicKey = "{$n}|{$e}",
encrypted = cryptico.encrypt("plain text", publicKey);
job is not finished yet. the result of cryptico.encrypt is NOT simply encrypted by RSA. indeed, it was combined of two parts: an aes key encrypted by RSA, and the cipher of the plain text encrypted with that aes key by AES. if we only need RSA, we could modify my.encrypt:
my.encrypt = function(plaintext, publickeystring, signingkey)
{
var cipherblock = "";
try
{
var publickey = my.publicKeyFromString(publickeystring);
cipherblock += my.b16to64(publickey.encrypt(plaintext));
}
catch(err)
{
return {status: "Invalid public key"};
}
return {status: "success", cipher: cipherblock};
}
now we are able to decrypt the cipher with openssl:
$private = openssl_pkey_get_private("YOUR PRIVATE KEY STRING IN PEM");
// $encrypted is the result of cryptico.encrypt() in javascript side
openssl_private_decrypt(base64_decode($encrypted), $decrypted, $private);
// now $decrypted holds the decrypted plain text