iOS7引入了新的GKLocalPlayer方法generateIdentityVerificationSignatureWithCompletionHandler()
。
有没有人知道如何用它来做好事?我假设在Apple服务器端会有一些公共API。
发布于 2014-01-03 03:04:53
以下是C# WebApi服务器端版本:
public class GameCenterController : ApiController
{
// POST api/gamecenter
public HttpResponseMessage Post(GameCenterAuth data)
{
string token;
if (ValidateSignature(data, out token))
{
return Request.CreateResponse(HttpStatusCode.OK, token);
}
return Request.CreateErrorResponse(HttpStatusCode.Forbidden, string.Empty);
}
private bool ValidateSignature(GameCenterAuth auth, out string token)
{
try
{
var cert = GetCertificate(auth.PublicKeyUrl);
if (cert.Verify())
{
var csp = cert.PublicKey.Key as RSACryptoServiceProvider;
if (csp != null)
{
var sha256 = new SHA256Managed();
var sig = ConcatSignature(auth.PlayerId, auth.BundleId, auth.Timestamp, auth.Salt);
var hash = sha256.ComputeHash(sig);
if (csp.VerifyHash(hash, CryptoConfig.MapNameToOID("SHA256"), Convert.FromBase64String(auth.Signature)))
{
// Valid user.
// Do server related user management stuff.
return true;
}
}
}
// Failure
token = null;
return false;
}
catch (Exception ex)
{
// Log the error
token = null;
return false;
}
}
private static byte[] ToBigEndian(ulong value)
{
var buffer = new byte[8];
for (int i = 0; i < 8; i++)
{
buffer[7 - i] = unchecked((byte)(value & 0xff));
value = value >> 8;
}
return buffer;
}
private X509Certificate2 GetCertificate(string url)
{
var client = new WebClient();
var rawData = client.DownloadData(url);
return new X509Certificate2(rawData);
}
private byte[] ConcatSignature(string playerId, string bundleId, ulong timestamp, string salt)
{
var data = new List<byte>();
data.AddRange(Encoding.UTF8.GetBytes(playerId));
data.AddRange(Encoding.UTF8.GetBytes(bundleId));
data.AddRange(ToBigEndian(timestamp));
data.AddRange(Convert.FromBase64String(salt));
return data.ToArray();
}
}
public class GameCenterAuth
{
public string PlayerId { get; set; }
public string BundleId { get; set; }
public string Name { get; set; }
public string PublicKeyUrl { get; set; }
public string Signature { get; set; }
public string Salt { get; set; }
public ulong Timestamp { get; set; }
}
发布于 2013-12-06 18:20:21
谢谢,@odyth。谢谢,@莱昂内尔。我想在这里添加Python版本(基于您的版本)。它有一个小缺陷-苹果证书没有被验证-在pyOpenSSL绑定上没有这样的API。
import urllib2
import OpenSSL
import struct
def authenticate_game_center_user(gc_public_key_url, app_bundle_id, gc_player_id, gc_timestamp, gc_salt, gc_unverified_signature):
apple_cert = urllib2.urlopen(gc_public_key_url).read()
gc_pkey_certificate = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_ASN1, apple_cert)
payload = gc_player_id.encode('UTF-8') + app_bundle_id.encode('UTF-8') + struct.pack('>Q', int(gc_timestamp)) + gc_salt
try:
OpenSSL.crypto.verify(gc_pkey_certificate, gc_unverified_signature, payload, 'sha1')
print 'Signature verification is done. Success!'
except Exception as res:
print res
public_key_url = 'https://sandbox.gc.apple.com/public-key/gc-sb.cer'
player_GC_ID = 'G:1870391344'
timestamp = '1382621610281'
your_app_bundle_id = 'com.myapp.bundle_id'
with open('./salt.dat', 'rb') as f_salt:
with open('./signature.dat', 'rb') as f_sign:
authenticate_game_center_user(public_key_url, your_app_bundle_id, player_GC_ID, timestamp, f_salt.read(), f_sign.read())
发布于 2015-01-08 04:00:01
添加了Python的答案,但使用了PyCrypto 2.6 (这是Google App Engine解决方案)。还要注意的是,这里没有在下载后验证公共证书,类似于上面使用OpenSSL的python答案。这一步真的有必要吗?如果我们检查到公钥URL是去往一个苹果域名,并且它使用的是ssl (https),这不是意味着它不会受到中间人攻击吗?
无论如何,这是代码。注意:在连接和使用之前,二进制文本被重新转换为二进制。此外,我还必须更新我的本地python安装以使用PyCrypto 2.6,然后才能工作:
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA
from base64 import b64decode
from Crypto.Util.asn1 import DerSequence
from binascii import a2b_base64
import struct
import urlparse
def authenticate_game_center_user(gc_public_key_url, app_bundle_id, gc_player_id, gc_timestamp, gc_salt, gc_unverified_signature):
apple_cert = urllib2.urlopen(gc_public_key_url).read()
#Verify the url is https and is pointing to an apple domain.
parts = urlparse.urlparse(gc_public_key_url)
domainName = ".apple.com"
domainLocation = len(parts[1]) - len(domainName)
actualLocation = parts[1].find(domainName)
if parts[0] != "https" or domainName not in parts[1] or domainLocation != actualLocation:
logging.warning("Public Key Url is invalid.")
raise Exception
cert = DerSequence()
cert.decode(apple_cert)
tbsCertificate = DerSequence()
tbsCertificate.decode(cert[0])
subjectPublicKeyInfo = tbsCertificate[6]
rsakey = RSA.importKey(subjectPublicKeyInfo)
verifier = PKCS1_v1_5.new(rsakey)
payload = gc_player_id.encode('UTF-8')
payload = payload + app_bundle_id.encode('UTF-8')
payload = payload + struct.pack('>Q', int(gc_timestamp))
payload = payload + b64decode(gc_salt)
digest = SHA.new(payload)
if verifier.verify(digest, b64decode(gc_unverified_signature)):
print "The signature is authentic."
else:
print "The signature is not authentic."
https://stackoverflow.com/questions/17408729
复制相似问题