I have a text config file. This file needs to be encrypted and shipped with the product so that the end user can not change the values.
I have looked into AES for doing this and come across this simple example.
import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import java.io.*;
/**
* This program generates a AES key, retrieves its raw bytes, and
* then reinstantiates a AES key from the key bytes.
* The reinstantiated key is used to initialize a AES cipher for
* encryption and decryption.
*/
public class AES
{
/**
* Turns array of bytes into string
*
* @param buf Array of bytes to convert to hex string
* @return Generated hex string
*/
public static String asHex(byte buf[])
{
StringBuilder strbuf = new StringBuilder(buf.length * 2);
int i;
for (i = 0; i < buf.length; i++)
{
if (((int) buf[i] & 0xff) < 0x10)
{
strbuf.append("0");
}
strbuf.append(Long.toString((int) buf[i] & 0xff, 16));
}
return strbuf.toString();
}
public static void main(String[] args) throws Exception
{
String message = "This is just an example";
// Get the KeyGenerator
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128); // 192 and 256 bits may not be available
// Generate the secret key specs.
SecretKey skey = kgen.generateKey();
byte[] raw = skey.getEncoded();
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
// Instantiate the cipher
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(message.getBytes());
System.out.println("encrypted string: " + asHex(encrypted));
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] original = cipher.doFinal(encrypted);
String originalString = new String(original);
System.out.println("Original string: " + originalString + " " + asHex(original));
}
}
Is this a good approach? I could get the config file as a string, encode it, write the encoded bytes to a file. I开发者_运维问答 could then distribute the encoded file.
On the other end though, how would I decipher it? How to I distribute the key spec so that it will be able to be deciphered?
Thanks
(Reposting a slightly abridged version of my comment as an answer, since it got several votes and I am quite convinced that this is the answer.)
You are facing the same problem as the movie and game industries, and the answer is: the best you can do is to make it hard for the user to change the file; you cannot make it impossible. The decryption key must necessarily reside somewhere in your code (or in the hardware, if you produce the hardware too), where it can be obtained by reverse engineering. You could encrypt the key too, but then the second key must be stored in your code, and so on. You'll get a similar problem if you decide to store a hash of the file in your code and use it to verify that the file has not been tampered with, because then someone could alter the hash inside your executable (Edit: or simply alter the code to skip the hash check entirely).
As @limc mentioned, you could go for some central verification scheme, with all the problems and user-hostility they bring. I think @Mr Jacques' suggestion is your best option unless you really need it to be 100% hack-proof (in which case I think you have a big problem), as it will deter the vast majority of users (until someone publishes a crack, that is...)
You could distribute the certificate as a separate jar file, with all the signing information. But you'd need to make sure that the certificate becomes invalid when used on other machines.
If your goal is to truly make it so that the user can not CHANGE the file, then you could calculate a simple hash of the file.
Hard code a "salt" to add to your hash and then store the hash in a second configuration file.
The user can see the file, but any changes will change the hash. Without knowing the secret salt, they can not generate a new hash.
There's really no foolproof way to solve this. I have noticed that some bigger software companies (Adobe, Microsoft, Symantec) require the user to authenticate against their servers to perform n-way-handshake to ensure the keys are valid. That works, but it introduces another set of problems... for example, user needs internet access, user needs to transfer serial to a new computer, etc...
In one of my projects I have worked on, I stored the encryption key in the user computer's registry. Granted, my project isn't a top-secret project and it doesn't prevent a more savvy user from searching the registry for the key. That is still better than hardcoding the encryption key in the source code especially if I have to version control the project.
精彩评论