2011-04-09 10 views
7

Tengo una aplicación de Android que proporciona facturación en la aplicación y tenemos nuestro servidor de aplicaciones al que se conecta la aplicación de Android para proporcionar servicios al usuario, en la aplicación compra queremos enviar el recibo al servidor para el proceso de verificación.Facturación en la aplicación de Android Verificación de recibo en Dot Net (C#)

Ahora problema es que no sé cómo convertir Security.java archivo en la red del punto (C#) como nuestro servidor está escrito en la red del punto

NOTA: Este archivo viene con Android facturación en la aplicación misma aplicación que ofrece funciones de firma de mensajes solo necesito su equivalente en dot net.

Más detalles sobre este problema está disponible en http://social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/66bb5683-fde6-47ca-92d7-de255cc8655a

Respuesta

3

he encontrado la solución, para lograr primero hay que convertir el formato de clave pública como punto net utiliza tipo de clave diferente como una entrada.

No conozco las otras formas, pero podemos obtener la clave de formato dot net usando un código java que debe ejecutarse solo una vez para generar la clave pública RSA friendly. (esto sólo se recomienda cuando el público dado no hacer cambios rápidamente, por ejemplo en caso de Android mercado de facturación en la aplicación)

siguiente código Java trabajó para mí

public static DotNetRSA GenerateDotNetKey(String base64PubKey) 
      throws IOException, NoSuchAlgorithmException, 
      InvalidKeySpecException { 
     /* 
     * String base64PubKey - 
     * Is a Key retrieved from Google Checkout Merchant Account 
     */ 
     BASE64Decoder decoder = new BASE64Decoder(); 

     byte[] publicKeyBytes = decoder.decodeBuffer(base64PubKey); 

     EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeyBytes); 
     RSAPublicKey publicKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(publicKeySpec); 

     byte[] modulusBytes = publicKey.getModulus().toByteArray(); 
     byte[] exponentBytes = publicKey.getPublicExponent().toByteArray(); 

     modulusBytes = stripLeadingZeros(modulusBytes); 

     BASE64Encoder encoder = new BASE64Encoder(); 
     String modulusB64 = encoder.encode(modulusBytes); 
     String exponentB64 = encoder.encode(exponentBytes); 

     return new DotNetRSA(modulusB64, exponentB64); 
    } 

     private static byte[] stripLeadingZeros(byte[] a) { 
     int lastZero = -1; 
     for (int i = 0; i < a.length; i++) { 
      if (a[i] == 0) { 
      lastZero = i; 
      } 
      else { 
      break; 
      } 
     } 
     lastZero++; 
     byte[] result = new byte[a.length - lastZero]; 
     System.arraycopy(a, lastZero, result, 0, result.length); 
     return result; 
     } 

Ahora para verificar la firma digital que pueda utilizar el siguiente código en su programa de la red del punto (C#) proporcionan GCHO_PUB_KEY_EXP es su exponente y GCHO_PUB_KEY_MOD es su módulo extraído por encima del código de Java

public static bool VerifyDataSingature(string data, string sign) 
{ 
    using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider()) 
    { 
     RSAParameters rsaKeyInfo = new RSAParameters() 
     { 
      Exponent = Convert.FromBase64String(GCHO_PUB_KEY_EXP), 
      Modulus = Convert.FromBase64String(GCHO_PUB_KEY_MOD) 
     }; 
     rsa.ImportParameters(rsaKeyInfo); 

     return rsa.VerifyData(Encoding.ASCII.GetBytes(data), 
           "SHA1", 
           Convert.FromBase64String(sign)); 
    } 
} 

espero que funcione para todos, ya que funcionó para mí. Gracias

mérito es de Code Project Artical

+0

Gracias por la solución! Es muy útil. – Michael

+0

¿Qué sucede si 'data' contiene caracteres que no son ASCII? Desde el nombre de la publicación, supongo que 'data' contendrá JSON, que es una cadena y permite caracteres que no sean ASCII. –

+0

@Ivan Akcheurov: no estoy seguro, este es definitivamente el primer borrador del código. entonces tal error es esperado. No recuerdo haber modificado el código yo mismo. –

1

FYI para píos búsqueda, aquí está el archivo Java completa, y la función en VB.NET.

/** 
* <p>Title: RSA Security</p> 
* Description: This class generates a RSA private and public key, reinstantiates 
* the keys from the corresponding key files.It also generates compatible .Net Public Key, 
* which we will read later in C# program using .Net Securtiy Framework 
* The reinstantiated keys are used to sign and verify the given data.</p> 
* 
* @author Shaheryar 
* @version 1.0 
*/ 

import java.security.*; 
import java.security.spec.*; 
import java.io.*; 
import java.security.interfaces.*; 
import java.security.cert.*; 
import javax.xml.transform.stream.*; 
import javax.xml.transform.dom.*; 
import javax.xml.transform.*; 
import org.w3c.dom.*; 
import javax.xml.parsers.*; 
import sun.misc.BASE64Decoder; 
import sun.misc.BASE64Encoder; 

public class SecurityManager { 

    private KeyPairGenerator keyGen; //Key pair generator for RSA 
    private PrivateKey privateKey; // Private Key Class 
    private PublicKey publicKey; // Public Key Class 
    private KeyPair keypair; // KeyPair Class 
    private Signature sign; // Signature, used to sign the data 
    private String PRIVATE_KEY_FILE; // Private key file. 
    private String PUBLIC_KEY_FILE; // Public key file. 
    private String DOT_NET_PUBLIC_KEY_FILE; // File to store .Net Compatible Key Data 

    /** 
    * Default Constructor. Instantiates the key paths and signature algorithm. 
* @throws IOException 
* @throws InvalidKeySpecException 
* @throws NoSuchAlgorithmException 
    */ 
    public SecurityManager() throws NoSuchAlgorithmException, InvalidKeySpecException, IOException { 

    } 


    public static void main(String args[]) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException{ 
     GenerateDotNetKey("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp6340BNzismmb/n98sTcYfNEmmzNGumdWnK1e7NNWntM6mjZMnQaVZ9HiJKmMgtn69dAU4gaMVUWACDsuup1GBxN8dLgDbtR26M0u1jf1G8AQehcKfqxqSYzxKquXXotffdYsJPpjseZbi96Y7j47kz9CjNP3y1BzjJNTWQUx9fc9e2Bpsi0GtqJ8porPBuIGTjcCnlKM14tIv6YlHtECW1L1wcOBkoj/5liI1nhlYDth/DNXg1OY11JqIIP1fO2vQPtKEpdtcTBTjmB9M45O1N8K/shTcMntFjwVTpL0hRd+eaN1bUjpMvrhFik0VcF/ZNN6Hn0Coqe+ey18dLosQIDAQAB"); 
    } 
    public static void GenerateDotNetKey(String base64PubKey) 
      throws IOException, NoSuchAlgorithmException, 
      InvalidKeySpecException { 
     /* 
     * String base64PubKey - 
     * Is a Key retrieved from Google Checkout Merchant Account 
     */ 
     BASE64Decoder decoder = new BASE64Decoder(); 

     byte[] publicKeyBytes = decoder.decodeBuffer(base64PubKey); 

     EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeyBytes); 
     RSAPublicKey publicKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(publicKeySpec); 

     byte[] modulusBytes = publicKey.getModulus().toByteArray(); 
     byte[] exponentBytes = publicKey.getPublicExponent().toByteArray(); 

     modulusBytes = stripLeadingZeros1(modulusBytes); 

     BASE64Encoder encoder = new BASE64Encoder(); 
     String modulusB64 = encoder.encode(modulusBytes); 
     String exponentB64 = encoder.encode(exponentBytes); 
int i=0; 
    // return new DotNetRSA(modulusB64, exponentB64); 
    } 

    private static byte[] stripLeadingZeros1(byte[] a) { 
     int lastZero = -1; 
     for (int i = 0; i < a.length; i++) { 
     if (a[i] == 0) { 
      lastZero = i; 
     } 
     else { 
      break; 
     } 
     } 
     lastZero++; 
     byte[] result = new byte[a.length - lastZero]; 
     System.arraycopy(a, lastZero, result, 0, result.length); 
     return result; 
    } 


    } 

acaba de agregar a un nuevo proyecto Java y se ejecuta como aplicación Java con un punto de quiebre (int i = 0;) para extraer las llaves, código no la mía, solo bodged por mí, los apoyos a la original autor, vínculo arriba

y VB.NET

Private Function VerifyDataSignature(ByVal data As String, ByVal sign As String) As Boolean 
    Using rsa As New RSACryptoServiceProvider() 
     Dim rsaKeyInfo As RSAParameters = New RSAParameters() 
     rsaKeyInfo.Exponent = Convert.FromBase64String("ExponentFromJava") 
     rsaKeyInfo.Modulus = Convert.FromBase64String("ModulusFromJava") 
     rsa.ImportParameters(rsaKeyInfo) 
     Return rsa.VerifyData(Encoding.ASCII.GetBytes(data), "SHA1", Convert.FromBase64String(sign)) 
    End Using 
End Function 
2

para todas las personas que necesiten verificar la firma aquí es una implementación completa de C# utilizando la DLL BouncyCastle para ayudar.

Si alimenta la clase con su clave pública de Google podrá verificar las firmas, sin la necesidad de ningún código Java. Diviértete con eso. grtz Martien

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

using Org.BouncyCastle.Security; 
using Org.BouncyCastle.Crypto; 
using Org.BouncyCastle.Crypto.Parameters; 
using System.Security.Cryptography; 

namespace GoogleEncryptTest 
{ 
    class GoogleSignatureVerify 
{ 
    RSAParameters _rsaKeyInfo; 

    public GoogleSignatureVerify(String GooglePublicKey) 
    { 
     RsaKeyParameters rsaParameters= (RsaKeyParameters) PublicKeyFactory.CreateKey(Convert.FromBase64String(GooglePublicKey)); 

     byte[] rsaExp = rsaParameters.Exponent.ToByteArray(); 
     byte[] Modulus = rsaParameters.Modulus.ToByteArray(); 

     // Microsoft RSAParameters modulo wants leading zero's removed so create new array with leading zero's removed 
     int Pos = 0; 
     for (int i=0; i<Modulus.Length; i++) 
     { 
      if (Modulus[i] == 0) 
      { 
       Pos++; 
      } 
      else 
      { 
       break; 
      } 
     } 
     byte[] rsaMod = new byte[Modulus.Length-Pos]; 
     Array.Copy(Modulus,Pos,rsaMod,0,Modulus.Length-Pos); 

     // Fill the Microsoft parameters 
     _rsaKeyInfo = new RSAParameters() 
     { 
      Exponent = rsaExp, 
      Modulus  = rsaMod 
     }; 
    } 

    public bool Verify(String Message,String Signature) 
    { 
     using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider()) 
     {  
      rsa.ImportParameters(_rsaKeyInfo); 
      return rsa.VerifyData(Encoding.ASCII.GetBytes(Message), "SHA1", Convert.FromBase64String(Signature)); 
     }   
    } 
} 
} 
+0

Funciona perfectamente ¡Gracias! – itay83

4

He aquí una aplicación C# puro, desde Checking Google Play Signatures on .Net.

Cree un proyecto de aplicación de consola para convertir la clave pública en el formato XML que RSACryptoServiceProvider espera. Agregue PEMKeyLoader.cs al proyecto de aplicación de la consola.

using PublicKeyConvert; 
using System.Security.Cryptography; 

namespace ConsoleApplication 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      RSACryptoServiceProvider provider = PEMKeyLoader.CryptoServiceProviderFromPublicKeyInfo(MY_BASE64_PUBLIC_KEY); 
      System.Console.WriteLine(provider.ToXmlString(false)); 
     } 

     const string MY_BASE64_PUBLIC_KEY = "Paste your base64 Google public key here."; 
    } 
} 

Ejecución de que la producción de aplicación de consola voluntad (en la consola) el formato XML que RSACryptoServiceProvider Espera.

Ahora que tiene su clave pública con formato XML, se puede usar verificar las firmas:

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); 
} 
Cuestiones relacionadas