Форум программистов, компьютерный форум CyberForum.ru

Программирование Android

Войти
Регистрация
Восстановить пароль
 
ILNAR_93
Android
217 / 217 / 21
Регистрация: 19.01.2013
Сообщений: 1,637
Записей в блоге: 3
#1

Проверка валидности покупки сторонним сервером - Android

20.11.2015, 13:23. Просмотров 291. Ответов 4
Метки нет (Все метки)

Возможно ли следующее:

Андроид устройства покупает контент через гугл и полученный JSON ответ отправляет на свой сервер, а этот сервер уже запрашивает сервер google на валидность покупки отправляя туда тот же JSON(идентификатор покупки)
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
20.11.2015, 13:23     Проверка валидности покупки сторонним сервером
Посмотрите здесь:

Приложение не соединяется с сервером. Почем? Android
Проверка internet connection. Проверка доступности сети Android
Android Обмен данными с сервером
Не могу соединиться с сервером Android
Факт оплаты покупки в приложении - где хранить? Android
Приложение с сервером Android
Соединение с сервером Apache Android
Покупки, подписки в приложении Android
Android Webview, добавить возможность покупки пакетов
покупки в приложении и id пользователя, скачавшего приложение Android
Android Пропадает соединение с сервером
Покупки в приложения в обход гугла Android

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Spelcrawler
525 / 495 / 111
Регистрация: 12.03.2014
Сообщений: 1,647
Завершенные тесты: 1
20.11.2015, 13:24     Проверка валидности покупки сторонним сервером #2
ILNAR_93, ага, именно так и нужно проверять.
ILNAR_93
Android
217 / 217 / 21
Регистрация: 19.01.2013
Сообщений: 1,637
Записей в блоге: 3
20.11.2015, 14:00  [ТС]     Проверка валидности покупки сторонним сервером #3
Spelcrawler, не подскажешь куда копать?)

Вот это не то?
Кликните здесь для просмотра всего текста
PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
function verify_market_in_app($signed_data, $signature, $public_key_base64) 
{
 $key = "-----BEGIN PUBLIC KEY-----\n".
  chunk_split($public_key_base64, 64,"\n").
  '-----END PUBLIC KEY-----';   
 //using PHP to create an RSA key
 $key = openssl_get_publickey($key);
 //$signature should be in binary format, but it comes as BASE64. 
 //So, I'll convert it.
 $signature = base64_decode($signature);   
 //using PHP's native support to verify the signature
 $result = openssl_verify(
   $signed_data,
   $signature,
   $key,
   OPENSSL_ALGO_SHA1);
 if (0 === $result) 
 {
  return false;
 }
 else if (1 !== $result)
 {
  return false;
 }
 else 
 {
  return true;
 }
}
Spelcrawler
525 / 495 / 111
Регистрация: 12.03.2014
Сообщений: 1,647
Завершенные тесты: 1
20.11.2015, 14:03     Проверка валидности покупки сторонним сервером #4
ILNAR_93, по серверной части не могу помочь. Но выглядит рабочим.
ILNAR_93
Android
217 / 217 / 21
Регистрация: 19.01.2013
Сообщений: 1,637
Записей в блоге: 3
03.12.2015, 16:36  [ТС]     Проверка валидности покупки сторонним сервером #5
Проверка валидности посредством C#

Ответ от suvitruf
Когда приходит результат покупки, то в поле `inapp_signed_data` у `Intent`'а будет сигнатура.
Теперь вам нужен RSA. Для C# вам надо его сгенерировать из публичного ключа из вашей консоли разработчика в GP:

C#
1
2
3
const string MY_BASE64_PUBLIC_KEY = "Ваш base64 Google публичный ключ";
    RSACryptoServiceProvider provider = PEMKeyLoader.CryptoServiceProviderFromPublicKeyInfo(MY_BASE64_PUBLIC_KEY);
    string xmlPublicKey = provider.ToXmlString(false);
Вот класс для этого:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Security.Cryptography;
    using System.IO;
    
    namespace PublicKeyConvert
    {
        public class PEMKeyLoader
        {
    
            // encoded OID sequence for  PKCS #1 rsaEncryption szOID_RSA_RSA = "1.2.840.113549.1.1.1"
            static byte[] SeqOID = { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00 };
    
            private static bool CompareBytearrays(byte[] a, byte[] b)
            {
                if (a.Length != b.Length)
                    return false;
                int i = 0;
                foreach (byte c in a)
                {
                    if (c != b[i])
                        return false;
                    i++;
                }
                return true;
            }
    
            public static RSACryptoServiceProvider CryptoServiceProviderFromPublicKeyInfo(byte[] x509key)
            {
                byte[] seq = new byte[15];
                int x509size;
    
                if (x509key == null || x509key.Length == 0)
                    return null;
                
                x509size = x509key.Length;
    
                // ---------  Set up stream to read the asn.1 encoded SubjectPublicKeyInfo blob  ------
                MemoryStream mem = new MemoryStream(x509key);
                BinaryReader binr = new BinaryReader(mem);    //wrap Memory Stream with BinaryReader for easy reading
                byte bt = 0;
                ushort twobytes = 0;
    
                try
                {
                    twobytes = binr.ReadUInt16();
                    if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
                        binr.ReadByte();    //advance 1 byte
                    else if (twobytes == 0x8230)
                        binr.ReadInt16();   //advance 2 bytes
                    else
                        return null;
    
                    seq = binr.ReadBytes(15);       //read the Sequence OID
                    if (!CompareBytearrays(seq, SeqOID))    //make sure Sequence for OID is correct
                        return null;
    
                    twobytes = binr.ReadUInt16();
                    if (twobytes == 0x8103) //data read as little endian order (actual data order for Bit String is 03 81)
                        binr.ReadByte();    //advance 1 byte
                    else if (twobytes == 0x8203)
                        binr.ReadInt16();   //advance 2 bytes
                    else
                        return null;
    
                    bt = binr.ReadByte();
                    if (bt != 0x00)     //expect null byte next
                        return null;
    
                    twobytes = binr.ReadUInt16();
                    if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
                        binr.ReadByte();    //advance 1 byte
                    else if (twobytes == 0x8230)
                        binr.ReadInt16();   //advance 2 bytes
                    else
                        return null;
    
                    twobytes = binr.ReadUInt16();
                    byte lowbyte = 0x00;
                    byte highbyte = 0x00;
    
                    if (twobytes == 0x8102) //data read as little endian order (actual data order for Integer is 02 81)
                        lowbyte = binr.ReadByte();  // read next bytes which is bytes in modulus
                    else if (twobytes == 0x8202)
                    {
                        highbyte = binr.ReadByte(); //advance 2 bytes
                        lowbyte = binr.ReadByte();
                    }
                    else
                        return null;
                    byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };   //reverse byte order since asn.1 key uses big endian order
                    int modsize = BitConverter.ToInt32(modint, 0);
    
                    int firstbyte = binr.PeekChar();
                    if (firstbyte == 0x00)
                    {   //if first byte (highest order) of modulus is zero, don't include it
                        binr.ReadByte();    //skip this null byte
                        modsize -= 1;   //reduce modulus buffer size by 1
                    }
    
                    byte[] modulus = binr.ReadBytes(modsize);   //read the modulus bytes
    
                    if (binr.ReadByte() != 0x02)            //expect an Integer for the exponent data
                        return null;
                    int expbytes = (int)binr.ReadByte();        // should only need one byte for actual exponent data (for all useful values)
                    byte[] exponent = binr.ReadBytes(expbytes);
    
    
                    // ------- create RSACryptoServiceProvider instance and initialize with public key -----
                    RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
                    RSAParameters RSAKeyInfo = new RSAParameters();
                    RSAKeyInfo.Modulus = modulus;
                    RSAKeyInfo.Exponent = exponent;
                    RSA.ImportParameters(RSAKeyInfo);
    
                    return RSA;
                }
                finally
                {
                    binr.Close();
                }
            }
    
            public static RSACryptoServiceProvider CryptoServiceProviderFromPublicKeyInfo(String base64EncodedKey)
            {
                try
                {
                    //see if the file is a valid Base64 encoded cert
                    return CryptoServiceProviderFromPublicKeyInfo(Convert.FromBase64String(base64EncodedKey));
                }
                catch (System.FormatException)
                {
                }
    
                return null;
            }
    
            public static byte[] X509KeyFromFile(String filename)
            {
                byte[] x509key;
    
                if (String.IsNullOrWhiteSpace(filename) || !File.Exists(filename))
                    return null;
    
                StreamReader sr = File.OpenText(filename);
                String filestr = sr.ReadToEnd();
                sr.Close();
                StringBuilder sb = new StringBuilder(filestr);
                sb.Replace("-----BEGIN PUBLIC KEY-----", "");  //remove headers/footers, if present
                sb.Replace("-----END PUBLIC KEY-----", "");
    
                try
                {   
                    //see if the file is a valid Base64 encoded cert
                    x509key = Convert.FromBase64String(sb.ToString());
                }
                catch (System.FormatException)
                {       
                    //if not a b64-encoded publiccert, assume it's binary
                    Stream stream = new FileStream(filename, FileMode.Open);
                    int datalen = (int)stream.Length;
                    x509key = new byte[datalen];
                    stream.Read(x509key, 0, datalen);
                    stream.Close();
                }
    
                return x509key;
            }
    
        }
    }
Теперь можно проверять подпись сообщения:


C#
1
2
3
4
5
6
7
8
9
10
11
12
13
 public static bool Verify(string message, string base64Signature, string xmlPublicKey){
        // Create the provider and load the KEY
        RSACryptoServiceProvider provider = new RSACryptoServiceProvider();
        provider.FromXmlString(xmlPublicKey);
    
        // The signature is supposed to be encoded in base64 and the SHA1 checksum
        // of the message is computed against the UTF-8 representation of the message
        byte[] signature = System.Convert.FromBase64String(base64Signature);
        SHA1Managed sha = new SHA1Managed();
        byte[] data = System.Text.Encoding.UTF8.GetBytes(message);
    
        return provider.VerifyData(data, sha, signature);
    }
`message` - это ваш JSON.
Yandex
Объявления
03.12.2015, 16:36     Проверка валидности покупки сторонним сервером
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru