有关"公钥的文档"由GKLocalPlayer返回generateIdentityVerificationSignatureWithCompletionHandler:?

时间:2014-11-13 02:00:43

标签: java game-center x509certificate

Apple是否有任何文档涵盖用于生成- [GKLocalPlayer generateIdentityVerificationSignatureWithCompletionHandler:]返回的文件的格式或算法?

我在SO上看到了关于验证用户的基本流程的few questions,这似乎表明该文件是.cer文件(application / pkix-cert),并且它使用DER文件格式,但我找不到Apple官方的任何内容。

我希望用Java验证证书,如果有人有任何例子,那么我也非常感激。

2 个答案:

答案 0 :(得分:2)

IOS

[localPlayer generateIdentityVerificationSignatureWithCompletionHandler:^(NSURL *publicKeyUrl, NSData *signature, NSData *salt, uint64_t timestamp, NSError *error) {
                if(error != nil){
                    //login failed.
                }else{
                    NSLog(@"signature : %@", [signature base64Encoding]);
                    NSLog(@"salt : %@", [salt base64Encoding]);
                    NSLog(@"PUBLIC_KEY_URL : %@", publicKeyUrl);
                    NSLog(@"signature : %@", [signature base64EncodedStringWithOptions:0]);
                    NSLog(@"salt : %@", [salt base64EncodedStringWithOptions:0]);
                    NSLog(@"timestamp : %lld", timestamp);

                    NSLog(@"Gamecenter login success.");

                    NSMutableData *payload = [[NSMutableData alloc] init];
                    [payload appendData:[[GKLocalPlayer localPlayer].playerID dataUsingEncoding:NSUTF8StringEncoding]];
                    [payload appendData:[[[NSBundle mainBundle] bundleIdentifier] dataUsingEncoding:NSUTF8StringEncoding]];
                    uint64_t timestampBE = CFSwapInt64HostToBig(timestamp);
                    [payload appendBytes:&timestampBE length:sizeof(timestampBE)];
                    [payload appendData:salt];

                    NSString *ext_id = localPlayer.playerID;
                    NSString *encodedSignedData = [payload base64EncodedStringWithOptions:0];
                    NSLog(@"SIGNEDDATA : %@", encodedSignedData);
                    NSString *encodedSignature  = [signature base64Encoding];
                    NSString *publicKeyUrlStr   = [publicKeyUrl absoluteString];

                }
            }];

java代码是..

public static String makeEncodedSignedDataForAppleVerify(String player_id, String bundle_id, String timestamp, String salt){
    return new String(Base64.encodeBase64(concat(player_id.getBytes(),
            bundle_id.getBytes(),
            ByteBuffer.allocate(8).putLong(Long.parseLong(timestamp)).array(), 
            Base64.decodeBase64(salt))));
}

public static boolean gamecenterUserVerify(String publicKeyUrl, String signedData, String signature){
    try{
        URL url = new URL(publicKeyUrl);

        HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();
        HttpURLConnection httpConn = (HttpURLConnection) urlConn;
        httpConn.setAllowUserInteraction(false);
        httpConn.connect();

        InputStream in = httpConn.getInputStream();
        BufferedInputStream bis = new BufferedInputStream(in);
        ByteArrayBuffer baf = new ByteArrayBuffer(99999);
        int read = 0;
        int bufSize = 512;
        byte[] buffer = new byte[bufSize];
        while(true){
            read = bis.read(buffer);
            if(read==-1){
                break;
            }
            baf.append(buffer, 0, read);
        }

        byte[] bytes =baf.toByteArray();
        bis.close();
        in.close();
        httpConn.disconnect();

        CertificateFactory cf =   CertificateFactory.getInstance("X509");
        X509Certificate c = (X509Certificate) 
        cf.generateCertificate(new ByteArrayInputStream(bytes) );

        PublicKey key22 = c.getPublicKey();

        byte[] result = Base64.decodeBase64(signedData);//;
        byte[] decodedSignature = Base64.decodeBase64(signature);

        Signature sig;
        try {
            sig = Signature.getInstance("SHA256withRSA");
            sig.initVerify(key22);
            sig.update(result);
            if (!sig.verify(decodedSignature)) {
                return false;
            }else{
                return true;
            }
        } catch (NoSuchAlgorithmException e) {
           e.printStackTrace();
        } catch (InvalidKeyException e) {
           e.printStackTrace();
        } catch (SignatureException e) {
           e.printStackTrace();
        }
    }catch(Exception e){
        e.printStackTrace();
    }

    return false;
}

static byte[] concat(byte[]...arrays)
{
    // Determine the length of the result array
    int totalLength = 0;
    for (int i = 0; i < arrays.length; i++)
    {
        totalLength += arrays[i].length;
    }

    // create the result array
    byte[] result = new byte[totalLength];

    // copy the source arrays into the result array
    int currentIndex = 0;
    for (int i = 0; i < arrays.length; i++)
    {
        System.arraycopy(arrays[i], 0, result, currentIndex, arrays[i].length);
        currentIndex += arrays[i].length;
    }

    return result;
}

答案 1 :(得分:0)

由于声誉不佳,我不能对chamnassi的解决方案发表评论:chamnassi的答案很有效

此外,还应添加以下检查:验证证书是否来自Apple。快速&amp;脏解决方案是验证URL源自&#34; apple.com&#34;:

// verify the URL: needs to have ".apple.com/" inside!
String path = publicKeyUrl;
path = path.substring(path.indexOf("://") + 3);  // cut protocol, e.g. "https://" from front
path = path.substring(0, path.indexOf("/"));     // cut the URL-path part, so we only have something list "whatever.apple.com"!
if (!path.toLowerCase().endsWith(".apple.com")) {
    // invalid certificate: not from Apple site!
    --> throw error
}