I am trying to create a signature then verify for a message of 40 bytes using the SHA-256 algorithm. I thought I did everything correctly, but it is giving me false for verification, and I cannot find out what I did wrong. I double and triple and quadruple checked, but couldn't find out. Any help would be appreciated.
here are the two functions I have created to sign and verify signature for a message.
public static byte[] sigAuth(byte[] message, File file, PrivateKey privateKey) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException, IOException{
SecretKeySpec secretKey = new SecretKeySpec(sharedKey, "hmacSHA256");
Mac macHMAC = Mac.getInstance("HmacSHA256");
macHMAC.init(secretKey);
byte[] authMessageInHMACC = macHMAC.doFinal(message);
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);
signature.update(authMessageInHMACC);
byte[] finalSignature = signature.sign();
FileOutputStream fos = new FileOutputStream(file);
fos.write(message);
fos.write(finalSignature);
fos.close();
return finalSignature;
}
public static boolean verify(File file, PublicKey pubKey) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException, IOException{
byte fileContent[] = new byte[(int)sharedKeyFile.length()];
FileInputStream fos = new FileInputStream(file);
fos.read(fileContent);
fos.close();
/Split message from signed hash
byte[] messageOnly = new byte[40];
byte[] hash = new byte[256];
//messageauthmessage
int j = 0;
int k = 0;
for (int i = 0; i < fileContent.length;i++){
if(i < 40){
messageOnly[i] = fileContent[i];
j++;
} else {
hash[k] = fileContent[j+1];
k++;
}
}
SecretKeySpec secretKey = new SecretKeySpec(sharedKey, "hmacSHA256");
Mac macHMAC = Mac.getInstance("HmacSHA256");
macHMAC.init(secretKey);
byte[] authMessageInHMACC = macHMAC.doFinal(messageOnly);
Signature pubSignature = Signature.getInstance("SHA256withRSA");
pubSignature.initVerify(pubKey);
pubSignature.update(authMessageInHMACC);
boolean verified = pubSignature.verify(hash);
return verified;
}
messageOnly[i] = fileContent[i];
should be
messageOnly[j] = fileContent[i];
and
hash[k] = fileContent[j+1];
should be
hash[k] = fileContent[i];
Related
I am new at flutter development, I am trying to use send ENCRYPTED data on server using a public key in flutter .
I have .cer certificate and i have RSA public key in flutter. Now in Java I'm using for Encrypt the Plain Text using RSA public key i have done this
successfully . How can i do this in flutter ?
public String encrypt(String string, final X509Certificate x509Certificate) throws NoSuchAlgorithmException, NoSuchPaddingException, IOException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException, InvalidAlgorithmParameterException {
Cipher a = Cipher.getInstance("RSA");
final KeyGenerator instance;
(instance = KeyGenerator.getInstance("AES")).init(256);
byte[] b = instance.generateKey().getEncoded();
System.out.println("print encoded key"+b);
printUnsignedBytes(b);
aesKey = b;
new SecretKeySpec(b, "AES");
a.init(1, x509Certificate.getPublicKey());
final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
final CipherOutputStream cipherOutputStream;
(cipherOutputStream = new CipherOutputStream(byteArrayOutputStream, a)).write(b);
cipherOutputStream.close();
byte[] c = byteArrayOutputStream.toByteArray();
final byte[] array = new byte[16];
new SecureRandom().nextBytes(array);
final Cipher instance2;
(instance2 = Cipher.getInstance("AES/CBC/NOPADDING")).init(1, new SecretKeySpec(b, "AES"),
new IvParameterSpec(array));
byte[] bytes = s.getBytes();
int remainder = 16 - (bytes.length % 16);
byte[] remainderFilledWithSpaces = new byte[remainder];
for (int i = 0; i < remainderFilledWithSpaces.length; i++) {
remainderFilledWithSpaces[i] = " ".getBytes()[0];
}
int totalLength = bytes.length + remainder;
ByteBuffer bb = ByteBuffer.allocate(totalLength);
bb.put(bytes);
bb.put(remainderFilledWithSpaces);
bb.position(0);
byte[] blockToEncrypt = new byte[16];
ByteBuffer encrypted = ByteBuffer.allocate(totalLength);
while (bb.hasRemaining()) {
bb.get(blockToEncrypt);
byte[] update = instance2.update(blockToEncrypt);
encrypted.put(update);
}
instance2.doFinal();
final ByteArrayOutputStream byteArrayOutputStream2 = new ByteArrayOutputStream();
final byte[] array2;
(array2 = new byte[4])[0] = 0;
array2[1] = 1;
array2[3] = (array2[2] = 0);
byteArrayOutputStream2.write(array2, 0, 4);
array2[0] = 16;
array2[1] = 0;
array2[3] = (array2[2] = 0);
byteArrayOutputStream2.write(array2, 0, 4);
byteArrayOutputStream2.write(c, 0, 256);
byteArrayOutputStream2.write(array, 0, 16);
byteArrayOutputStream2.write(encrypted.array());
return s = new String(Base64.getMimeEncoder().encode(byteArrayOutputStream2.toByteArray()));
}
Now , I want this same solution in Dart .Please help,thanks a lot.
I am trying to decrypt files by Java and below codes work. However it will have OutOfMemory exception when decrypting large files. I tried to change to cipher.update but the program will freeze without any responding.
How can I change this from doFinal to update?
public File decryptDataFile(File inputFile, File outputFile, File keyFile, String correlationId) {
try {
Security.addProvider(new BouncyCastleProvider());
String key = new String(Files.readAllBytes(keyFile.toPath())).trim();
byte[] byteInput = this.getFileInBytes(inputFile);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding", "BC");
byte[] salt = new byte[8];
System.arraycopy(byteInput, 8, salt, 0, 8);
SecretKeyFactory fact = SecretKeyFactory.getInstance("PBEWITHMD5AND256BITAES-CBC-OPENSSL", "BC");
cipher.init(Cipher.DECRYPT_MODE, fact.generateSecret(new PBEKeySpec(key.toCharArray(), salt, 100)));
byte[] data = cipher.doFinal(byteInput, 16, byteInput.length-16);
OutputStream os = new FileOutputStream(outputFile);
os.write(data);
os.close();
if(outputFile.exists()) {
return outputFile;
} else {
return null;
}
} catch (IOException | NoSuchAlgorithmException | NoSuchProviderException | NoSuchPaddingException | InvalidKeyException | InvalidKeySpecException | IllegalBlockSizeException | BadPaddingException e) {
logger.WriteLog(appConfig.getPlatform(), "INFO", alsConfig.getProjectCode(), correlationId, alsConfig.getFunctionId(), "SCAN_DECRYPT", e.getClass().getCanonicalName() + " - " + e.getMessage() );
return null;
}
}
My non-working version:
Security.addProvider(new BouncyCastleProvider());
String key = new String(Files.readAllBytes(keyFile.toPath())).trim();
byte[] byteInput = this.getFileInBytes(inputFile);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding", "BC");
byte[] salt = new byte[8];
System.arraycopy(byteInput, 8, salt, 0, 8);
SecretKeyFactory fact = SecretKeyFactory.getInstance("PBEWITHMD5AND256BITAES-CBC-OPENSSL", "BC");
cipher.init(Cipher.DECRYPT_MODE, fact.generateSecret(new PBEKeySpec(key.toCharArray(), salt, 100)));
FileInputStream fis = new FileInputStream(inputFile);
FileOutputStream fos = new FileOutputStream(outputFile);
CipherInputStream cis = new CipherInputStream(fis, cipher);
int b;
byte[] d = new byte[8];
while((b = cis.read(d)) != -1) {
fos.write(d, 0, b);
}
fos.flush();
fos.close();
cis.close();
if(outputFile.exists()) {
return outputFile;
} else {
return null;
}
Foreword: I couldn't decrypt with your original method a file that was encrypted with your openssl-command
openssl enc -aes-256-cbc -e -salt -in ${tarFile} -out ${encTarFile} -pass file:./${KEY_RANDOM}
but the following method should decode even large files similar to your original method - I tested files up to 1 GB size.
Edit: Regarding the OpenSSL statement, it's worth mentioning that since v1.1.0 the default digest has changed from MD5 to SHA256,
so for higher versions the -md MD5 option must be set explicitly for compatibility with the Java code. (thanks to #Topaco).
Please keep in mind that I don't care about correct file paths for
new FileInputStream(inputFile.toPath().toString())
and
new FileOutputStream(outputFile.toPath().toString())
as I'm working locally and with my folder, maybe you have to change the code to "find" your files. As well there is no exception handling in this example.
The code line
byte[] ibuf = new byte[8096];
is defining the buffer that is used - a larger buffer makes the decryption faster but consumes more memory (8096 means 8096 byte compared to 1 Gbyte when reading the complete file into memory and causing the out of memory error).
public static File decryptDataFileBuffered(File inputFile, File outputFile, File keyFile, String correlationId) throws IOException, NoSuchPaddingException, NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException, BadPaddingException, IllegalBlockSizeException, InvalidKeyException {
Security.addProvider(new BouncyCastleProvider());
String key = new String(Files.readAllBytes(keyFile.toPath())).trim();
byte[] salt = new byte[8];
byte[] salted = new byte[8]; // text SALTED__
try (FileInputStream in = new FileInputStream(inputFile.toPath().toString()); // i don't care about the path as all is lokal
FileOutputStream out = new FileOutputStream(outputFile.toPath().toString())) // i don't care about the path as all is lokal
{
byte[] ibuf = new byte[8096]; // thats the buffer used - larger is faster
int len;
in.read(salted);
in.read(salt);
SecretKeyFactory fact = SecretKeyFactory.getInstance("PBEWITHMD5AND256BITAES-CBC-OPENSSL", "BC");
SecretKey secretKey = fact.generateSecret(new PBEKeySpec(key.toCharArray(), salt, 100));
System.out.println("secretKey length: " + secretKey.getEncoded().length + " data: " + bytesToHex(secretKey.getEncoded()));
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
while ((len = in.read(ibuf)) != -1) {
byte[] obuf = cipher.update(ibuf, 0, len);
if (obuf != null)
out.write(obuf);
}
byte[] obuf = cipher.doFinal();
if (obuf != null)
out.write(obuf);
} catch (IOException | BadPaddingException | IllegalBlockSizeException e) {
e.printStackTrace();
}
if (outputFile.exists()) {
return outputFile;
} else {
return null;
}
}
Edit2: As commented by #Topaco the usage of CipherInput/OutputStream shortens the code and makes it better readable, so here is the code:
public static File decryptDataFileBufferedCipherInputStream (File inputFile, File outputFile, File keyFile, String correlationId) throws
IOException, NoSuchPaddingException, NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException, InvalidKeyException
{
Security.addProvider(new BouncyCastleProvider());
String key = new String(Files.readAllBytes(keyFile.toPath())).trim();
byte[] salt = new byte[8];
byte[] salted = new byte[8]; // text SALTED__
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
try (FileInputStream in = new FileInputStream(inputFile.toPath().toString()); // i don't care about the path as all is lokal
CipherInputStream cipherInputStream = new CipherInputStream(in, cipher);
FileOutputStream out = new FileOutputStream(outputFile.toPath().toString())) // i don't care about the path as all is lokal
{
byte[] buffer = new byte[8192];
in.read(salted);
in.read(salt);
SecretKeyFactory fact = SecretKeyFactory.getInstance("PBEWITHMD5AND256BITAES-CBC-OPENSSL", "BC");
SecretKey secretKey = fact.generateSecret(new PBEKeySpec(key.toCharArray(), salt, 100));
System.out.println("secretKey length: " + secretKey.getEncoded().length + " data: " + bytesToHex(secretKey.getEncoded()));
cipher.init(Cipher.DECRYPT_MODE, secretKey);
int nread;
while ((nread = cipherInputStream.read(buffer)) > 0) {
out.write(buffer, 0, nread);
}
out.flush();
}
if (outputFile.exists()) {
return outputFile;
} else {
return null;
}
}
I received an encrypted string from Java, and I can see the Java encrypted source code.
I wrote the decryption code in C#. But always report an error at "FlushFinalBlock". Error message: "System.Security.Cryptography.CryptographicException. Additional information: Incorrect data."
Can any body point out where the problem is in my C# code?
this is java code:
private static byte[] coderByDES(byte[] plainText, String key, int mode)
throws InvalidKeyException, InvalidKeySpecException,
NoSuchAlgorithmException, NoSuchPaddingException,
BadPaddingException, IllegalBlockSizeException,
UnsupportedEncodingException {
SecureRandom sr = new SecureRandom();
byte[] resultKey = makeKey(key);
DESKeySpec desSpec = new DESKeySpec(resultKey);
SecretKey secretKey = SecretKeyFactory.getInstance("DES").generateSecret(desSpec);
Cipher cipher = Cipher.getInstance("DES");
cipher.init(mode, secretKey, sr);
return cipher.doFinal(plainText);
}
private static byte[] makeKey(String key)
throws UnsupportedEncodingException {
byte[] keyByte = new byte[8];
byte[] keyResult = key.getBytes("UTF-8");
for (int i = 0; i < keyResult.length && i < keyByte.length; i++) {
keyByte[i] = keyResult[i];
}
return keyByte;
}
private static String byteArr2HexStr(byte[] arrB) {
int iLen = arrB.length;
StringBuilder sb = new StringBuilder(iLen * 2);
for (int i = 0; i < iLen; i++) {
int intTmp = arrB[i];
while (intTmp < 0) {
intTmp = intTmp + 256;
}
if (intTmp < 16) {
sb.append("0");
}
sb.append(Integer.toString(intTmp, 16));
}
return sb.toString();
}
this is C# code:
public static string DecryptForDES(string input, string key)
{
byte[] inputByteArray = HexStr2ByteArr(input);
byte[] buffArray = null;
using (DESCryptoServiceProvider des = new DESCryptoServiceProvider())
{
des.Key = Encoding.UTF8.GetBytes(key);
des.IV = Encoding.UTF8.GetBytes(key);
des.Mode = System.Security.Cryptography.CipherMode.ECB;
des.Padding = PaddingMode.PKCS7;
System.IO.MemoryStream ms = new System.IO.MemoryStream();
using (CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(inputByteArray, 0, inputByteArray.Length);
cs.FlushFinalBlock();//
cs.Close();
}
buffArray = ms.ToArray();
ms.Close();
}
string str = string.Empty;
if (buffArray != null)
{
str = Encoding.UTF8.GetString(buffArray);
}
return str;
}
public static byte[] HexStr2ByteArr(string strIn)
{
byte[] arrB = Encoding.UTF8.GetBytes(strIn);
int iLen = arrB.Length;
byte[] arrOut = new byte[iLen / 2];
byte[] arrTmp = new byte[2];
for (int i = 0; i < iLen; i = i + 2)
{
string strTmp = Encoding.UTF8.GetString(arrB, i, 2);
arrOut[i / 2] = (byte)Convert.ToInt32(strTmp, 16);
}
return arrOut;
}
Both, the Java encryption part and the C# decryption part work on my machine if the passwords match. Otherwise a System.Security.Cryptography.CryptographicException: 'Bad Data' is thrown. To get the password match replace in the C#-method DecryptForDES
des.Key = Encoding.UTF8.GetBytes(key);
with
des.Key = MakeKey(key);
with the C#-method:
private static byte[] MakeKey(String key)
{
byte[] keyByte = new byte[8];
byte[] keyResult = Encoding.UTF8.GetBytes(key);
for (int i = 0; i<keyResult.Length && i<keyByte.Length; i++) {
keyByte[i] = keyResult[i];
}
return keyByte;
}
corresponding to the Java-method makeKey(String key).
Moreover, remove in the C#-method DecryptForDES
des.IV = Encoding.UTF8.GetBytes(key);
since the ECB-mode doesn't use an IV.
In the following testcase
coderByDES("This is a plain text that needs to be encrypted...", "This is the key used for encryption...", Cipher.ENCRYPT_MODE);
returns the byte-array
a47b1b2c90fb3b7a0ab1f51f328ff55aae3c1eb7789c31c28346696a8b1f27c7413c14e68fe977d3235b5a6f63c07d7a95d912ff22f17ad6
and
DecryptForDES("a47b1b2c90fb3b7a0ab1f51f328ff55aae3c1eb7789c31c28346696a8b1f27c7413c14e68fe977d3235b5a6f63c07d7a95d912ff22f17ad6", "This is the key used for encryption...");
returns the correct plain text.
By the way: As Flydog57 already stated DES is insecure (https://en.wikipedia.org/wiki/Data_Encryption_Standard). And also the ECB mode is not secure (https://crypto.stackexchange.com/questions/20941/why-shouldnt-i-use-ecb-encryption).
Better choices are AES (https://en.wikipedia.org/wiki/Advanced_Encryption_Standard) with CBC or GCM mode (https://crypto.stackexchange.com/questions/2310/what-is-the-difference-between-cbc-and-gcm-mode).
I am trying to encrypt and decrypt files with BouncyCastle 3DES. But the files are corrupted after encrypting and decrypting. For example a simple text-file or a jpg-image-file. This is my Code:
ZipUnzipBouncyCastle()
{
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
}
public void encrypt3DES(String password, String file)
throws IOException, DataLengthException, IllegalStateException,
InvalidCipherTextException, NoSuchAlgorithmException
{
byte[] data = Files.readAllBytes(new File(file).toPath());
SecureRandom random = new SecureRandom(data);
KeyGenerator keyGenerator = KeyGenerator.getInstance("DESede");
keyGenerator.init(168, random);
SecretKey secreteKey = keyGenerator.generateKey();
BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new DESedeEngine()));
cipher.init(true, new KeyParameter(secreteKey.getEncoded()));
byte[] result = new byte[cipher.getOutputSize(data.length)];
int tam = cipher.processBytes(data, 0, data.length, result, 0);
cipher.doFinal(result, tam);
byte[] encodedData = Base64.getEncoder().encode(result);
FileOutputStream fileOutputStream = new FileOutputStream(file);
fileOutputStream.write(encodedData);
fileOutputStream.flush();
fileOutputStream.close();
}
public void decrypt3DES(String password, String file)
throws NoSuchAlgorithmException, DataLengthException,
IllegalStateException, InvalidCipherTextException, IOException
{
byte[] data = Files.readAllBytes(new File(file).toPath());
byte[] decodedData = Base64.getDecoder().decode(data);
SecureRandom random = new SecureRandom(decodedData);
KeyGenerator keyGenerator = KeyGenerator.getInstance("DESede");
keyGenerator.init(168, random);
SecretKey secreteKey = keyGenerator.generateKey();
BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new DESedeEngine()));
cipher.init(true, new KeyParameter(secreteKey.getEncoded()));
byte[] result = new byte[cipher.getOutputSize(decodedData.length)];
int tam = cipher.processBytes(decodedData, 0, decodedData.length, result, 0);
cipher.doFinal(result, tam);
FileOutputStream fileOutputStream = new FileOutputStream(file);
fileOutputStream.write(result);
fileOutputStream.flush();
fileOutputStream.close();
}
I looked all over the Internet but could not find any explanation. What am I doing wrong?
I tried convert it to byte[] and store it on a bytea but it didn't work, i don't receive the same secretkey that i stored. Using type String didn't work as well
if you're interested in more details, my application is to crypt and decrypt pictures using AES and these are methods to crypt and decrypt
public void crypt() throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, InvalidKeyException, IOException{
Cipher cipher = Cipher.getInstance("AES");
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
SecretKey secKey = keyGen.generateKey();
byte[] encoded = secKey.getEncoded();
this.setCodeCrypt(encoded);
cipher.init(Cipher.ENCRYPT_MODE, secKey);
String cleartextFile = this.lien;
String ciphertextFile = "crypted img.jpg";
FileInputStream fis = new FileInputStream(cleartextFile);
FileOutputStream fos = new FileOutputStream(ciphertextFile);
CipherOutputStream cos = new CipherOutputStream(fos, cipher);
int i;
while ((i = fis.read()) != -1) {
cos.write(i);
}
cos.close();
}
// Decrypt
public void decrypt() throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, InvalidKeyException, IOException{
try {
Class.forName("org.postgresql.Driver");
String url = "jdbc:postgresql://localhost:5432/papiersadmin";
String user = "postgres";
String passwd = "postgresql";
java.sql.Connection conn = DriverManager.getConnection(url, user,passwd);
Statement state = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
// loading a picture knowing its path (lien)
ResultSet result = state.executeQuery("SELECT * FROM image WHERE lien = '"+this.lien+"'");
while(result.next()){
setCodeCrypt(result.getObject(6).toString().getBytes());}
state.close();
} catch (Exception e) {
e.printStackTrace();
}
Cipher cipher = Cipher.getInstance("AES");
SecretKey originalKey = new SecretKeySpec(codeCrypt, 0, codeCrypt.length, "AES");
cipher.init(Cipher.DECRYPT_MODE, originalKey);
String cleartextFile = "decrypted img.jpg";
String ciphertextFile = this.lien;
FileInputStream fis = new FileInputStream(ciphertextFile);
FileOutputStream fos = new FileOutputStream(cleartextFile);
CipherOutputStream cos = new CipherOutputStream(fos, cipher);
int i;
while ((i = fis.read()) != -1) {
cos.write(i);
}
cos.close();
}
Converting a byte[] to a String using toString() and then calling getBytes() will not do anything useful. I would suggest starting with ResultSet.getBytes().