I am trying to decrypt chromes encrypted field, but i get the following exception :-
Exception in thread "main" java.lang.AbstractMethodError: com.sun.jna.Structure.getFieldOrder()Ljava/util/List;
at com.sun.jna.Structure.fieldOrder(Structure.java:868)
at com.sun.jna.Structure.getFields(Structure.java:894)
at com.sun.jna.Structure.deriveLayout(Structure.java:1042)
at com.sun.jna.Structure.calculateSize(Structure.java:966)
at com.sun.jna.Structure.calculateSize(Structure.java:933)
at com.sun.jna.Structure.allocateMemory(Structure.java:360)
at com.sun.jna.Structure.<init>(Structure.java:184)
at com.sun.jna.Structure.<init>(Structure.java:172)
at com.sun.jna.Structure.<init>(Structure.java:159)
at com.sun.jna.Structure.<init>(Structure.java:151)
at com.sun.jna.platform.win32.WinCrypt$DATA_BLOB.<init>(WinCrypt.java:42)
at com.sun.jna.platform.win32.Crypt32Util.cryptUnprotectData(Crypt32Util.java:121)
at com.sun.jna.platform.win32.Crypt32Util.cryptUnprotectData(Crypt32Util.java:103)
at com.sun.jna.platform.win32.Crypt32Util.cryptUnprotectData(Crypt32Util.java:90)
at JPasswordManager.ChromeManager.main(ChromeManager.java:8)
Here is a snippet from my chrome class (Edit here is a sample code note - password field can be some other encrypted field i just quickly set it to that...):-
public static void main(String[] args)
{
try
{
Class.forName("org.sqlite.JDBC");
connection = DriverManager.getConnection("jdbc:sqlite:\\Users\\Standard User\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\Login Data");
resultSet = statement.executeQuery("SELECT username_value, password_value FROM logins"); // some encrypted field
while (resultSet.next())
{
byte[] encryptedData = resultSet.getBytes(1);
byte[] decryptedData = Crypt32Util.cryptUnprotectData(encryptedData); // exception over here
StringBuilder decryptedString = new StringBuilder();
for (byte b : decryptedData)
{
decryptedString .append((char) b);
}
System.out.println("decrypted = [" + decryptedString + "]");
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
i have also tried converting to hexString and then decrypting, that too did not work in case if you are intrested in knowing how i had converted to hex then here is a method that i coded
public static String ToHexString(byte[] bytes)
{
StringBuilder sb = new StringBuilder();
Formatter formatter = new Formatter(sb);
for (byte b : bytes)
{
formatter.format("%02x", b);
}
return sb.toString();
}
i used to pass encryptedData variable through this method and then try to cryptUnprotect the data but still it did not work..
Related
I have to send the AES encrypted json as content to web server. But after decryption, the content has extra trash symbols appeared at the beggining of the line.
My test method creates the object that is serialized and being send:
[TestMethod]
public void SendModeChangeWorksAsExpected()
{
var snpashot2Send = new ModeChangedReport
{
ControlWorkMode = ModeEnumeration.Stopped,
//Controls
ControlDate = DateTime.Now,
IsSent = false,
SentTime = null,
ReportType = ReportType.ModeChanged,
Line = new Line
{
AgencyId = "a799eb4f-86da-4af1-a221-9ed8b741b5ce"
}
};
//Создаём шифрованное значение
var encryptedString = _agencyReportEncriptingTranslator.ConvertModeChange2CypheredString(snpashot2Send);
//Отправляем в Агентство и получаем результат
var value = _agencyClient.SendModeChangeReport(encryptedString);
}
Here are the serialization and encrypt methods:
public string ConvertModeChange2CypheredString(ModeChangedReport report)
{
if (report == null) throw new ArgumentNullException(nameof(report));
//obj to json
var json = new ModeChangedReportJson
{
LineId = report.Line.AgencyId,
Mode = CreateModeFromIktToUzbekistan(report.ControlWorkMode),
ActionDate = ConvertDateToAgencyString(report.ControlDate)
};
//Serialization
var retString = _agencyJsonSerializer.SerializeReport2Json(json);
//Шифруем сериализованный json
var cypheredValue = _encryptionService.EncryptString(retString);
return cypheredValue;
}
Encrypt method:
public string EncryptString(string plaintext)
{
var plainTextBytes = Encoding.UTF8.GetBytes(plaintext);
var cypheredTextBytes = Encrypt(plainTextBytes);
var converted2Base64Value = Convert.ToBase64String(cypheredTextBytes);
return converted2Base64Value;
}
private byte[] Encrypt(byte[] bytes)
{
#region Args Validation
if (bytes == null || bytes.Length < 1)
{
throw new ArgumentException("Invalid bytes to encrypt");
}
if (_key == null || _key.Length < 1)
{
throw new InvalidOperationException("Invalid encryption key");
}
#endregion
byte[] encrypted;
try
{
using (AesManaged aes = new AesManaged())
{
aes.Key = _key;
aes.IV = _iv;
aes.Padding = PaddingMode.PKCS7;
aes.Mode = CipherMode.CBC;
ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, _iv);
using (MemoryStream ms = new MemoryStream())
{
ms.Write(aes.IV, 0, aes.IV.Length);
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
cs.Write(bytes, 0, bytes.Length);
}
encrypted = ms.ToArray();
}
}
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
return encrypted;
}
Http client send method:
public bool SendModeChangeReport(string cypheredValue)
{
var token = GetAccessToken();
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token.AuthorizationToken);
client.DefaultRequestHeaders.Add("DEVICE_ID", _agencyAppSettings.DeviceId);
var content2Post = new StringContent(cypheredValue, Encoding.UTF8, "application/json");
using (var response = client.PostAsync(_agencyAppSettings.SendModeChangedReportUrl, content2Post).Result)
{
string tokenResponse = null;
try
{
tokenResponse = response.Content.ReadAsStringAsync().Result;
response.EnsureSuccessStatusCode();
return true;
}
catch (Exception ex)
{
_eventLogManager.LogError("При попытке отправить отчёт о смене режима, произошла ошибка: "
+ $"Код: {response.StatusCode}. Контент: {tokenResponse}. Ошибка: {ex.Message}.");
return false;
}
}
}
}
After decryption on receiving server, the string grows with extra trash characters at the beginning, like G���h R��EQ�Z {"lineid":"a799eb4f-86da-4af1-a221-9ed8b741b5ce"...
The decrypt method of the server (Java):
I think that the problem is the padding difference: PKCS7 on my side, and PKCS5 on server.
How can I solve this problem with the extra chars appear on server side?
Those aren't trash characters, they're the Unicode Replacement Character returned when bytes are decoded into text using the wrong character set.
The very fact you got readable text means decrypting succeeded. It's decoding the bytes into text that failed.
The bug is in the Java code. It's using the String(byte[]) which, according to the docs:
Constructs a new String by decoding the specified array of bytes using the platform's default charset.
That's obviously not UTF8. The String(byte[] bytes,Charset charset) or String(byte[] bytes,String charsetName) constructors should be used instead, passing the correct character set, eg :
byte[] decryptedBytes = cipher.doFinal(....);
return new String(decryptedBytes, StandardCharsets.UTF_8);
The hacky alternative is to change the remote server's default character set to UTF8.
I would appreciate your help to understand why my SHA256 encryption function in JAVA and in PYTHON does not produce the result (difference in 1 digit, one more in python):
hash to encrypt is: "thisisatest"
Java results is: a7c96262c21db9a06fd49e307d694fd95f624569f9b35bb3ffacd88044f9787
Python result is:
a7c96262c21db9a06fd49e307d694fd95f624569f9b35bb3ffacd880440f9787
Python code:
import hashlib
def encrypt_string(hash_string):
sha_signature = \
hashlib.sha256(hash_string.encode()).hexdigest()
return sha_signature
hash_string = "thisisatest"
print(encrypt_string(hash_string), end="")
Java code:
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class OpenAPIPasswordEncryptor1 {
private static MessageDigest sha256;
// generated password is stored encrypted (using also user name for hashing)
public synchronized static String encrypt(String hash) {
try {
StringBuilder builder = new StringBuilder();
builder.append(hash);
// first time , encrypt user name , password and static key
String encryptedCredentials = encryptionIterator(builder.toString());
return encryptedCredentials;
}
catch (Exception e) {
e.printStackTrace();
}
return "";
}
private static String encryptionIterator(String content) {
try {
sha256 = MessageDigest.getInstance("SHA-256");
// append the static key to each iteration
byte[] passBytes = (content).getBytes();
sha256.reset();
byte[] digested = sha256.digest(passBytes);
StringBuffer sb = new StringBuffer();
for (int i = 0; i < digested.length; i++) {
sb.append(Integer.toHexString(0xff & digested[i]));
}
return sb.toString();
} catch (NoSuchAlgorithmException ex) {
ex.printStackTrace();
}
return "";
}
// generate password for developers
public static void main(String[] args) {
String hash = "thisisatest";
String encrypt = encrypt(hash);
System.out.println("Your Password Is '" + encrypt + "'");
}
}
The problem is that Integer.toHexString(int) drops the leading zero if the (unsigned) byte value is 15 or less. As a quick workaround, you could use this:
sb.append(String.format("%02x", 0xff & digested[i]));
Although more efficient implementations are certainly possible.
To produce the same bug in Python, use this:
def encrypt_string(hash_string):
sha_signature = hashlib.sha256(hash_string.encode()).digest()
return "".join(["{:x}".format(b) for b in sha_signature])
I'm a newbie in Java, I'm trying to sent a byte [] array via socket, but it itself convert my array to string and then sends it. so far it's ok, but the problem is that I need to either receive the message in array type, OR I have to convert the string to array, in order to make the decrypt method be able to decrypt the array (the input of decrypt method must be byte array). how can I do that?
my serverside related code is:
private void IssuingTickets() throws Exception{
String socketUsername = reader.readLine();//rcv username
String socketPassword = reader.readLine();//rcv password
writer.println("Lemme Check!");
Properties prop = new Properties();
prop.load(new FileInputStream("input"));
String fileUsername = prop.getProperty("username");
String filePassword = null;
if (prop.getProperty("password") != null) {
filePassword = prop.getProperty("password");}
if (socketPassword.equals(filePassword)){
String sessionKeyBobKdc = new Scanner(new File("sBOBandKDC")).useDelimiter("\\Z").next();
byte[] ClientTicket = encrypt(sessionKeyBobKdc, filePassword);
System.out.println("clietn ticket = " + ClientTicket+" ArraytoString " + Arrays.toString(ClientTicket));
writer.println(ClientTicket);
String KDCkey = new Scanner(new File("KDCkey")).useDelimiter("\\Z").next();
String UnEncTGT= sessionKeyBobKdc.concat(socketUsername);
byte[] TGT = encrypt(UnEncTGT, KDCkey);
writer.println(TGT);
}else
{writer.println("Please try again later!");}
}
public static byte[] encrypt(String plainText1, String encryptionKey) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding", "SunJCE");
SecretKeySpec key = new SecretKeySpec(encryptionKey.getBytes("UTF-8"), "AES");
cipher.init(Cipher.ENCRYPT_MODE, key,new IvParameterSpec(IV.getBytes("UTF-8")));
return cipher.doFinal(plainText1.getBytes("UTF-8"));
}
public static String decrypt(byte[] cipherText, String encryptionKey) throws Exception{
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding", "SunJCE");
SecretKeySpec key = new SecretKeySpec(encryptionKey.getBytes("UTF-8"), "AES");
cipher.init(Cipher.DECRYPT_MODE, key,new IvParameterSpec(IV.getBytes("UTF-8")));
return new String(cipher.doFinal(cipherText),"UTF-8");
}
}
the Clientside related code is:
private void recieveTickts() throws IOException, InterruptedException, Exception{
String msg = reader.readLine(); //Lemme check
System.out.println("Server :" + msg);
TimeUnit.SECONDS.sleep(3);
String Sth = reader.readLine(); //please try again
if(Sth.equals("Please try again later!")){
System.out.println(Sth);
System.exit(1);
}else{
ClientTicket = Sth;
String TGT = reader.readLine();
System.out.println("Encrypted key between Client and KDC is " + ClientTicket + " and the TGT is " + TGT);
TimeUnit.SECONDS.sleep(3);
System.out.println("SUCCESSFUL"); }
byte[] b = ClientTicket.getBytes();
System.out.println("b= " + b);
String sessionKeyBobKdc = decrypt(b, Password);
System.out.println(Password + "session key is "+ sessionKeyBobKdc);
}
thanx in advanced guys..
I documented the code to help you out but that is basically a quick and dirty way to never stop listening for data and then also return the received as byte[]. If you don't need to listen at all times just modify this code to stop listening once you received your message
You can make this more dynamic with using parameters for defining the sign that a message is finished etc.
I used a StringBuilder to act as a little buffer. And defined that a message is finished once I receive a LF. Everything else get's put into the "buffer". Additionally I filter out CR since I don't want them in my message.
Socket client;
StringBuilder sb = new StringBuilder();
String result = "";
int c;
try
{
InputStream inputStream = client.getInputStream();
while ( ( c = inputStream.read() ) >= 0 ) // Loop to listen for data until the connection is dead
{
if ( c == 0x0a ) // 0x0a is the hex for a LineFeed ( LF )
{
result = sb.toString(); // put everything you received so far as a final message
sb.delete( 0, sb.length() ); // clear your message "buffer"
}
else if ( c != 0x0d /* <CR> */ ) // Not necessary but it helps keeping the message clear
{
sb.append( (char) c ); // add the received integer as char to the message "buffer"
}
if ( !result.isEmpty() ) // Catch that a message is received
{
log.fine( "received message: " + result ); // just log for tracing
return result.getBytes(StandardCharsets.UTF_8); // return the byte[] of the message with the needed Charset.
}
}
}
catch ( Exception e )
{
log.warning( e.getMessage() );
}
sample.log contains
FLTR TID: 0000003756 RPC ID: 0000108159 Queue: Admin Client-RPC: 390626 USER: **[B#4783165b** Overlay-Group: 1
I need it to be like this
FLTR TID: 0000003756 RPC ID: 0000108159 Queue: Admin Client-RPC: 390626 USER: "DECRYPTED VALUE" Overlay-Group: 1
Use secret key as
String key = "ThisIsASecretKey";
This is what i have tried please edit wherever i wrote wrong code..
public class Decrypt {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("sample.log"));
String newStr = null;
String value = "";
while ((newStr = br.readLine()) != null) {
String next = null;
if (newStr.contains("FLTR")) {
next = newStr.substring(97, 135); // this gets string **[B#4783165b**
String collect = CallToDecrypt(next, value);
system.out.println(collect);
}
}
pt.close();
br.close();
}
private static String CallToDecrypt(String next, String value) {
String key = "ThisIsASecretKey";
byte[] raw = key.getBytes(Charset.forName("US-ASCII"));
if (raw.length != 16) {
throw new IllegalArgumentException("Invalid key size.");
}
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, new IvParameterSpec(new byte[16]));
byte[] original = cipher.doFinal();
return new String(original, Charset.forName("US-ASCII"));
}
}
Thanks to each one of you
You are tying to decrypt nothing right now: the String next is never used in the CallToDecrypt routine.
You will have to do something like
byte[] original = cipher.doFinal(next.getBytes());
I have a method which is generating HMAC value from public and private key.
Here is my method code:
String mykey = "fb6a1271f98099ac96cc0002d5e8022b";
String test = "json6b17f33e25e2d8197462d1c6bcb0b1302156641988";
try {
Mac mac = Mac.getInstance("HmacSHA1");
SecretKeySpec secret = new SecretKeySpec(mykey.getBytes(),
"HmacSHA1");
mac.init(secret);
byte[] digest = mac.doFinal(test.getBytes());
for (byte b : digest) {
System.out.format("%02x", b);
}
System.out.println();
} catch (Exception e) {
System.out.println(e.getMessage());
}
Now as per requirement, I need to use the value returned from it as String.
Here is the value returned from method in
System.out.format("%02x", b); =bd0aea241e88c8a22692eba02887ad97a220f827
Please help me..
I would recommend something like this (use a StringBuilder)
StringBuilder sb = new StringBuilder(digest.length * 2);
Formatter formatter = new Formatter(sb);
for (byte b : digest) {
formatter.format("%02x", b);
}
return sb.toString();
BigInteger has excellent base conversion facilities if you are looking for the HEX form of the string:
return new BigInteger(mac.doFinal(test.getBytes())).toString(16);