I'm trying to decrypt a Windows WiFi password on the same machine using Java which is supposed to work with cryptUnprotectData() but I'm getting the following error:
Exception in thread "main" com.sun.jna.platform.win32.Win32Exception: The data is invalid.
at com.sun.jna.platform.win32.Crypt32Util.cryptUnprotectData(Crypt32Util.java:128)
at com.sun.jna.platform.win32.Crypt32Util.cryptUnprotectData(Crypt32Util.java:103)
at com.sun.jna.platform.win32.Crypt32Util.cryptUnprotectData(Crypt32Util.java:90)
I'm using this Java code:
String encryptedWirelessKey = "01000000D08C9DDF0115D1118C7A00C0***TRUNCATED***";
byte[] bytes = Crypt32Util.cryptUnprotectData(encryptedWirelessKey.getBytes(Charset.defaultCharset()));
System.out.println(new String(bytes));
Here you can read more about where Windows stores WiFi passwords. Why is the data invalid when I copied it straight from the XML keyMaterial tags? I'm administrator on the machine and the passwords are by my user account.
Update:
import com.sun.jna.platform.win32.Crypt32Util;
public class Testing
{
public static void main(String[] arguments) throws Exception
{
String encryptedWirelessKey = "01000000D08C9DDF0115D1118C7A00C0***TRUNCATED***";
byte[] bytes = Crypt32Util.cryptUnprotectData(hexStringToByteArray(encryptedWirelessKey));
System.out.println(new String(bytes));
}
private static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
}
This throws the following exception:
Exception in thread "main" com.sun.jna.platform.win32.Win32Exception: Key not valid for use in specified state.
at com.sun.jna.platform.win32.Crypt32Util.cryptUnprotectData(Crypt32Util.java:128)
at com.sun.jna.platform.win32.Crypt32Util.cryptUnprotectData(Crypt32Util.java:103)
at com.sun.jna.platform.win32.Crypt32Util.cryptUnprotectData(Crypt32Util.java:90)
What exactly does it mean? Lacking permissions?
You're using getBytes() on a hex string, when you should be parsing the hex string into bytes.
Choose your preferred way from the following links.
In Java, how do I convert a hex string to a byte[]?
Convert a string representation of a hex dump to a byte array using Java?
Related
I'm working with some Android Java code that uses ECDSA keys. The code compiles and runs fine, but has some logic errors during the verification process. I want to try using a constant key pair (that's known to be valid) to troubleshoot the program.
Using an online generator, I got an EC public key in hex,
0x044fb7cebbb1f4a1e0412c8e0b6f2d675ebfee000c5e860a81ffd795b5743033dec0e114abfba3de8db8705fc8ed985c5550c66a6ee9fdd258d058a2ef749eba78
As well as a valid private key to complete the pair,
0x0c84e7e707b31ecf0254e8cb3040513883d92d81e977ad4754a409a6ab18ee51
I can convert the hex string to a primitive byte array, but that byte array appears to be invalid. I cannot figure out how to convert a hex representation of my keys to a X509 representation so that I can make a Java key object.
KeyFactory mFactory = KeyFactory.getInstance("EC");
X509EncodedKeySpec mPublicKey = new X509EncodedKeySpec(publicKeyBytes);
PublicKey publicKey = mFactory.generatePublic(mPublicKey);
That code results in:
java.security.spec.InvalidKeySpecException: com.android.org.conscrypt.OpenSSLX509CertificateFactory$ParsingException: Error parsing public key
I am reasonably sure that my conversion from hex string to byte array is working, but I'll include that method as well for a sanity check.
private static byte[] hexStringToByteArray(String s) throws IllegalArgumentException {
int len = s.length();
if (len % 2 == 1) {
throw new IllegalArgumentException("Hex string must have even number of characters");
}
byte[] data = new byte[len / 2]; // Allocate 1 byte per 2 hex characters
for (int i = 0; i < len; i += 2) {
// Convert each character into a integer (base-16), then bit-shift into place
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
The end goal is to have a constant, valid PublicKey/PrivateKey object for testing. Any advice about how to generate those objects would be greatly appreciated.
This question already has answers here:
Encode string to base32 string in Java
(2 answers)
Closed 5 years ago.
I am using google authenticator for TOTP generation and it uses a base32 encoded string to do so.
The secret that I have is Hex encoded and I need to convert it to Base32 before I can use it.
The following site does it perfectly, but I need it in JAVA.
: http://tomeko.net/online_tools/hex_to_base32.php?lang=en
I am very new to encoding and decoding. Any thoughts on how to go about it?
Okay, It was fairly simple. All I had to do was decode the Hex to a byte[] array and then encode it to Base32 using Apache Commons Codec Java library
This is the code
String hexToConvert = "446a1837e14bfec34a9q0141a55ec020f73e15f4";
byte[] hexData = hexStringToByteArray(hexToConvert);
Base32 base32 = new Base32();
String encodeBase32 = base32.encodeAsString(hexData);
System.out.println("Base 32 String: " + encodeBase32);
Helper Function: this is from Convert a string representation of a hex dump to a byte array using Java?
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
I use the following code for generating md5 for blob data in database.
md5Checksum.update(byte[] --- read from database);
String result = new BigInteger(1,md5Checksum.digest()).toString(16);
The checksum i obtain is varying in length(30-32) for different byte arrays.
For 31 char length checksum, as I understood can be an effect of the removal of leading zeros. (I handled it by adding leading zeros)
Can any one tell me why I am getting a 30 char hash in some cases?
Thanks,
Mithun
Do not convert a digest to a number!
Use something like:
byte[] b = md5Checksum.digest();
// now convert these bytes to chars
There are many different methods to convert byte[] to HexStrings:
public class HexConverter {
// thanks to http://www.rgagnon.com/javadetails/java-0596.html
static private final String HEXES = "0123456789ABCDEF";
public String toHex(byte[] raw) {
if (raw == null) {
return null;
}
final StringBuilder hex = new StringBuilder(2 * raw.length);
for (final byte b : raw) {
hex.append(HEXES.charAt((b & 0xF0) >> 4)).append(HEXES.charAt((b & 0x0F)));
}
return hex.toString();
}
}
or from Getting a File's MD5 Checksum in Java
(this link also shows how to se DigestUtils from Apache Commons Codec)
public static String getMD5Checksum(String filename) throws Exception {
byte[] b = createChecksum(filename);
String result = "";
for (int i=0; i < b.length; i++) {
result += Integer.toString( ( b[i] & 0xff ) + 0x100, 16).substring( 1 );
}
return result;
}
There is a chance that the high n bits could be zero. As you convert the byte[] to a number.If n=4,then you could lose one '0' char at the beginning.
If n=8, then you lose '00' at the beginning of your md5 hex code.
I'm trying to achieve this:
I have a PDF byte[] in java web service that I must send as a base64 string to a .NET client that does this to reconstruct the file.
Encoding.Convert(Encoding.Unicode, Encoding.Default, Convert.FromBase64String(inputJava))
I cannot change the client code and right now the java web service is calling another .NET web service that does this to turn the byte[] into a base64 string:
System.Text.Encoding.Convert(System.Text.Encoding.GetEncoding(1252), System.Text.Encoding.Unicode, b);
Beside the base64 that I can make in various ways (e.g. with org.apache.commons.codec.binary.Base64), I have to turn the original byte[] into a UTF-16LE byte[]...
I tried this:
byte[] output = new byte[b.length * 2];
for(int i=0; i < b.length; i++)
{
int val = b[i];
if(val < 0) val += 256;
output[2*i + 0] = (byte) (val);
output[2*i + 1] = 0;
}
This works fine for values below 128 (e.g. for 1 => 0100, 2 => 0200, ... , 127 => 7F00) but for values above (128 -> 255) I don't know how to get the equivalent 2bytes values; I know that for byte 156 (9C) the corresponding value is 8301 (0x5301) and for byte 224 (E0) the corresponding value is 12501 (0x7D01) but I didn't manage to find an algorithm to get all the other values.
Is there a mapping table between byte value and the corresponding UTF-16LE surrogate pair or an algorithm to map values from 128 to 255?
Thanks in advance!
You don’t need surrogate pairs; they are a construct for dealing with characters outside Basic Multilingual Plane (BMP), and all windows-1252 characters are in BMP.
The official windows-1252 (alias cp1252) to Unicode mapping table is
http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1252.TXT
It’s a plain text file in easy-to-process format, so if you don’t find an existing tool for the conversion, it should be rather straightforward to write mapping based on that file.
The file is indirectly cited in the official IANA registry:
http://www.iana.org/assignments/character-sets
byte[] encoded = new String(b, "windows-1252").getBytes("UTF-16LE");
I finally found a solution. It looks like that only bytes from 128 to 159 need the surrogate pairs. I use this piece of code to emulate .NET Unicode encoding:
public class Encoder {
static Map<Integer, Integer> mapTiny = new HashMap<Integer, Integer>() {
public Integer get(Object key) {
Integer code = super.get(key);
if (code == null)
code = (Integer) key;
return code;
}
};
static {
mapTiny.put(128,8364);
mapTiny.put(130,8218);
mapTiny.put(131,402);
mapTiny.put(132,8222);
mapTiny.put(133,8230);
mapTiny.put(134,8224);
mapTiny.put(135,8225);
mapTiny.put(136,710);
mapTiny.put(137,8240);
mapTiny.put(138,352);
mapTiny.put(139,8249);
mapTiny.put(140,338);
mapTiny.put(142,381);
mapTiny.put(145,8216);
mapTiny.put(146,8217);
mapTiny.put(147,8220);
mapTiny.put(148,8221);
mapTiny.put(149,8226);
mapTiny.put(150,8211);
mapTiny.put(151,8212);
mapTiny.put(152,732);
mapTiny.put(153,8482);
mapTiny.put(154,353);
mapTiny.put(155,8250);
mapTiny.put(156,339);
mapTiny.put(158,382);
mapTiny.put(159,376);
}
public static String encode(byte[] b) throws IOException {
ByteArrayInputStream in = new ByteArrayInputStream(b);
ByteArrayOutputStream convFileByteArray = new ByteArrayOutputStream();
int i = in.read();
while (i != -1) {
convFileByteArray.write(new byte[] { (byte) (mapTiny.get(i) & 0xff), (byte) ((mapTiny.get(i) >> 8) & 0xff) });
i = in.read();
}
return Base64.encodeToString(convFileByteArray.toByteArray(), false);
}
}
in the last 5 hours im trying to do something that should be very simple and did it in like 10 minutes in C#, but no luck with Java.
I got a 32 UpperCase and Numeric String (A-Z0-9), I need to convert this String to Dec, and then md5 it.
My problem is that I dont have unsgined bytes so I cant md5 my array :\
Here is what I need to do in python:
salt = words[1].decode("hex")
passwordHash = generatePasswordHash(salt, pw)
generatePasswordHash(salt, password):
m = md5.new()
m.update(salt)
m.update(password)
return m.digest()
and here it is in C# :
public static string GeneratePasswordHash(byte[] a_bSalt, string strData) {
MD5 md5Hasher = MD5.Create();
byte[] a_bCombined = new byte[a_bSalt.Length + strData.Length];
a_bSalt.CopyTo(a_bCombined, 0);
Encoding.Default.GetBytes(strData).CopyTo(a_bCombined, a_bSalt.Length);
byte[] a_bHash = md5Hasher.ComputeHash(a_bCombined);
StringBuilder sbStringifyHash = new StringBuilder();
for (int i = 0; i < a_bHash.Length; i++) {
sbStringifyHash.Append(a_bHash[i].ToString("X2"));
}
return sbStringifyHash.ToString();
}
protected byte[] HashToByteArray(string strHexString) {
byte[] a_bReturn = new byte[strHexString.Length / 2];
for (int i = 0; i < a_bReturn.Length; i++) {
a_bReturn[i] = Convert.ToByte(strHexString.Substring(i * 2, 2), 16);
}
return a_bReturn;
}
I will be very happy to get a help with this :)
To parse a hex string into a byte : (byte) Integer.parseInt(s, 16).
To transform your password string into a byte array, using the default encoding (which I suggest not to do : always specify a specific encoding) : password.getBytes() (or password.getBytes(encoding) for a specific encoding).
To hash a byte array : MessageDigest.getInstance("MD5").digest(byte[]).
To transform a byte to a hex String : See In Java, how do I convert a byte array to a string of hex digits while keeping leading zeros?
I believe that something like the following will work:
// convert your hex string to bytes
BigInteger bigInt = new BigInteger(salt, 16);
byte[] bytes = bigInt.toByteArray();
// get the MD5 digest library
MessageDigest md5Digest = null;
try {
md5Digest = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
// error handling here...
}
// by default big integer outputs a 0 sign byte if the first bit is set
if (bigInt.testBit(0)) {
md5Digest.update(bytes, 1, bytes.length - 1);
} else {
md5Digest.update(bytes);
}
// get the digest bytes
byte[] digestBytes = md5Digest.digest();
Here's more ideas for converting a hex string to a byte[] array:
Convert a string representation of a hex dump to a byte array using Java?
You can use unsigned numbers in java with applying bit masks. Take a look details here.