有趣的问题让我试验了一下。但是,正如你可能已经猜到的那样,我之前没有这样做过。但也许别人可以证实我的想法 - 或反驳他们,但请不要downvoting;)
我会使用一个asymmetric algorithm如RSA签名的字符串,包括所有的数据必须匹配才能有效。此签名与公钥一起存储,以便在无需访问服务器的情况下对其进行验证。
表现为Java代码,这应该是这样的(基于Signature Sign and Verify):
import java.security.*;
public class Main {
public static void main(String args[]) throws Exception {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
// our server, imagine it's a webservice
KeyServer server = new KeyServer(42);
// init client with a copy of public key from server
KeyClient client = new KeyClient(server.getPublicKey());
// create string that identifies phone and application
byte[] data = (getPhoneId() + ":" + getApplicationId()).getBytes("utf-8");
// send data to server for signature creation
byte[] digitalSignature = server.signData(data);
// verify on client side
System.out.println("verified = " + client.verifySig(data, digitalSignature));
// bad data
byte[] wrongData = ("anotherPhoneId" + ":" + getApplicationId()).getBytes("utf-8");
System.out.println("verified = " + client.verifySig(wrongData, digitalSignature));
// bad signature
digitalSignature[5] = (byte) 0xff;
System.out.println("verified = " + client.verifySig(data, digitalSignature));
}
private static String getPhoneId() {
return "somephone";
}
private static String getApplicationId() {
return "someapp";
}
public static class KeyClient {
private PublicKey _publicKey;
private Signature _signer;
public KeyClient(PublicKey publicKey) {
if (publicKey == null) {
throw new NullPointerException("publicKey");
}
_publicKey = publicKey;
try {
_signer = Signature.getInstance("SHA1withRSA");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("failed to get Signature", e);
}
}
public boolean verifySig(byte[] data, byte[] sig) throws Exception {
synchronized (_signer) {
_signer.initVerify(_publicKey);
_signer.update(data);
return (_signer.verify(sig));
}
}
}
public static class KeyServer {
private KeyPair _keyPair;
private Signature _signer;
public KeyServer(int seed) {
try {
_keyPair = generateKeyPair(seed);
} catch (Exception e) {
throw new RuntimeException("failed to generate key pair for seed " + seed, e);
}
try {
_signer = Signature.getInstance("SHA1withRSA");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("failed to get Signature", e);
}
}
public PublicKey getPublicKey() {
return _keyPair.getPublic();
}
public byte[] signData(byte[] data) throws InvalidKeyException, SignatureException {
synchronized (_signer) {
_signer.initSign(_keyPair.getPrivate());
_signer.update(data);
return (_signer.sign());
}
}
private KeyPair generateKeyPair(long seed) throws Exception {
KeyPairGenerator keyGenerator = KeyPairGenerator.getInstance("RSA");
SecureRandom rng = SecureRandom.getInstance("SHA1PRNG", "SUN");
rng.setSeed(seed);
keyGenerator.initialize(2048, rng);
return (keyGenerator.generateKeyPair());
}
}
}
@jax - 你有成功研究这个问题吗?我也在寻找一个安全的激活密钥生成器。 – Stevko 2010-06-09 22:00:20
是的,我现在正在抛弃它 - 我可以告诉你这是#$%$中的一大痛苦。 – jax 2010-06-10 04:33:08
关于这个话题的信息很少,当你问一个问题的时候,人们告诉你,如果你不明白你不应该这样做 - 我认为这是完全荒谬的 - 人们如何学习!一旦我完成我的API,我可能会从doridprofessor.com出售它。但是,如果想让您拥有自己的产品,请查看andappstore.com,他们已经为您提供了在线服务。你可以看看他们的代码并对其进行逆向工程。 Commons Base64类对于将二进制许可证编码为文本可读形式也非常有用。 – jax 2010-06-10 04:34:05