使用此处概述的Apple的Game Center身份验证验证步骤,已使用Java实现了以下验证逻辑。但是,这总是失败。
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.spec.AlgorithmParameterSpec;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.xml.bind.DatatypeConverter;
public class Verifier {
public static void main(String[] args) {
verify1();
}
public static void verify1() {
try {
byte[] playerID = "G:90082947".getBytes("UTF-8");
byte[] bundleID = "com.appledts.GameCenterSamples".getBytes("UTF-8");
long ts = 1392078336714L;
final ByteBuffer tsByteBuffer = ByteBuffer.allocate(8);
tsByteBuffer.order(ByteOrder.BIG_ENDIAN);
tsByteBuffer.putLong(ts);
byte[] timestamp = tsByteBuffer.array();
byte[] salt = DatatypeConverter.parseBase64Binary("xmvbZQ==");
byte[] sigToCheck = DatatypeConverter.parseBase64Binary("AmyNbm+7wJOjXv6GXI/vAEcl6gSX1AKxPr3GeExSYCiaxVaAeIvC23TWtp1/Vd/szfq1r1OzwrvkHeSSiskWMsMXaGQWUmiGtCnf9fqBU75T5PwNLCj4H9Nd5QENCMV/CFgVyGEi4X6Wlp18kqJPk/ooS6jLJwcWIe6DyrR1bQHl6YzKTfB4ACl2JEccBDz8dArKTrh4vFcQF4a+DtERm283Y2ue1DwG8lqWrYhsRO5v7vrW3lVpn5t25QXc+Y35zJ/il+lZJxKAgASwrKaq3G8RStdkeXCER23fSYhTmbLFqkFRWnmzu38hmLt5/iivUbm8NgELXP0SyQoYLMvfmA==");
ByteBuffer dataBuffer = ByteBuffer.allocate(playerID.length+bundleID.length+8+salt.length)
.put(playerID)
.put(bundleID)
.put(timestamp)
.put(salt);
Certificate cert = CertificateFactory.getInstance("X.509")
.generateCertificate(new URL("https://sandbox.gc.apple.com/public-key/gc-sb.cer").openConnection().getInputStream());
Signature sig = Signature.getInstance("SHA1withRSA");
sig.initVerify(cert);
sig.update(dataBuffer);
final boolean verify = sig.verify(sigToCheck);
System.out.println("signature verifies: " + verify);
} catch (Exception e) {
e.printStackTrace();
}
}
}
从iOS 7客户端向服务器传输数据时,不会丢失任何比特。通过将二进制位写入来自xCode和Java的文件中,生成它们的十六进制,并查看是否存在任何差异(请注意,差异仅显示文件名diff)来验证这一点:
$ xxd -i salt_Java.txt salt_java.xxd
$ xxd -i salt_xcode.txt salt_xcode.xxd
$ xxd -i sigToCheck_Java.txt sigToCheck_java.xxd
$ xxd -i sigToCheck_xcode.txt sigToCheck_xcode.xxd
$ diff salt_java.xxd salt_xcode.xxd
1c1
< unsigned char salt_Java_txt[] = {
---
> unsigned char salt_xcode_txt[] = {
4c4
< unsigned int salt_Java_txt_len = 4;
---
> unsigned int salt_xcode_txt_len = 4;
$ diff sigToCheck_java.xxd sigToCheck_xcode.xxd
1c1
< unsigned char sigToCheck_Java_txt[] = {
---
> unsigned char sigToCheck_xcode_txt[] = {
25c25
< unsigned int sigToCheck_Java_txt_len = 256;
---
> unsigned int sigToCheck_xcode_txt_len = 256;
$
我认为这失败是因为Signature类使用了底层Java库,因为此处列出的Objective-C解决方案似乎可以成功验证相同的凭据。
我的下一个尝试是使用Java的[Cipher]和[MessageDigest]库而不是[Signature]库,但这也失败了。我怀疑在使用提供的签名位检查签名摘要位之前,还缺少其他步骤。
final MessageDigest md = MessageDigest.getInstance("SHA1");
byte[] digest = md.digest(dataBuffer.array());
// RSA decrypt
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, cert);
byte[] decrypted = cipher.doFinal(sigToCheck);
System.out.println("signature verifies: " + Arrays.equals(digest, decrypted));
在上面发布的解决方案中,是否可以使用其他方法来验证数字签名或存在任何空白?
问题似乎出在传递给Signature.update()的ByteBuffer上。如果通过更改传递基础数组
sig.update(dataBuffer);
至
sig.update(dataBuffer.array());
验证似乎成功。根据Signature.update(ByteBuffer)的文档,我怀疑这是因为它试图从您在缓冲区中写入的最后一个位置读取数据,而未找到任何数据。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句