Porting Java Encryption Program in C #

I am trying with little success to port Google code to create a secure token for their captcha ( https://github.com/google/recaptcha-java/blob/master/appengine/src/main/java/com/google/recaptcha/STokenUtils .java ):

The source utility has the following:

private static final String CIPHER_INSTANCE_NAME = "AES/ECB/PKCS5Padding"; private static String encryptAes(String input, String siteSecret) { try { SecretKeySpec secretKey = getKey(siteSecret); Cipher cipher = Cipher.getInstance(CIPHER_INSTANCE_NAME); cipher.init(Cipher.ENCRYPT_MODE, secretKey); return BaseEncoding.base64Url().omitPadding().encode(cipher.doFinal(input.getBytes("UTF-8"))); } catch (Exception e) { e.printStackTrace(); } return null; } private static SecretKeySpec getKey(String siteSecret){ try { byte[] key = siteSecret.getBytes("UTF-8"); key = Arrays.copyOf(MessageDigest.getInstance("SHA").digest(key), 16); return new SecretKeySpec(key, "AES"); } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) { e.printStackTrace(); } return null; } public static void main(String [] args) throws Exception { //Hard coded the following to get a repeatable result String siteSecret = "12345678"; String jsonToken = "{'session_id':'abf52ca5-9d87-4061-b109-334abb7e637a','ts_ms':1445705791480}"; System.out.println(" json token: " + jsonToken); System.out.println(" siteSecret: " + siteSecret); System.out.println(" Encrypted stoken: " + encryptAes(jsonToken, siteSecret)); 

Given the values ​​that I hard-coded, I return Irez-rWkCEqnsiRLWfol0IXQu1JPs3qL_G_9HfUViMG9u4XhffHqAyju6SRvMhFS86czHX9s1tbzd6B15r1vmY6s5S8odXT-ZE9A-y1lHns" .

My Java and cryptography skills are more than rusty, and C # doesn't always have direct analogues. I tried combining encrypeAes() and getKey() with the following, which is wrong:

 public static string EncryptText(string PlainText, string siteSecret) { using (RijndaelManaged aes = new RijndaelManaged()) { aes.Mode = CipherMode.ECB; aes.Padding = PaddingMode.PKCS7; var bytes = Encoding.UTF8.GetBytes(siteSecret); SHA1 sha1 = SHA1.Create(); var shaKey = sha1.ComputeHash(bytes); byte[] targetArray = new byte[16]; Array.Copy(shaKey, targetArray, 16); aes.Key = targetArray; ICryptoTransform encrypto = aes.CreateEncryptor(); byte[] plainTextByte = ASCIIEncoding.UTF8.GetBytes(PlainText); byte[] CipherText = encrypto.TransformFinalBlock(plainTextByte, 0, plainTextByte.Length); return HttpServerUtility.UrlTokenEncode(CipherText); //Equivalent to java BaseEncoding.base64Url()? } } 

The C # version creates the wrong value: Ye+fySvneVUZJXth67+Si/e8fBUV4Sxs7wEXVDEOJjBMHl1encvt65gGIj8CiFzBGp5uUgKYJZCuQ4rc964vZigjlrJ/430LgYcathLLd9U=

+5
source share
2 answers

Your code works almost as expected. It’s just that you somehow mixed the outputs of the Java version (and, possibly, the C # version).

If I execute your Java code (JDK 7 and 8 with Guava 18.0), I get

  Ye-fySvneVUZJXth67-Si_e8fBUV4Sxs7wEXVDEOJjBMHl1encvt65gGIj8CiFzBGp5uUgKYJZCuQ4rc964vZigjlrJ_430LgYcathLLd9U

and if I execute your C # code ( DEMO ), I get

  Ye-fySvneVUZJXth67-Si_e8fBUV4Sxs7wEXVDEOJjBMHl1encvt65gGIj8CiFzBGp5uUgKYJZCuQ4rc964vZigjlrJ_430LgYcathLLd9U1

So, the C # version has an extra β€œ1” at the end. It should be a filling character, but it is not. This means that HttpServerUtility.UrlTokenEncode() does not provide standard compatibility with Base64 encoding, compatible with standards, and you should not use it. See also this Q & A.

Base64's secure encoding with URLs can easily be obtained from normal Base64 encoding (compare tables 1 and 2 in RFC4648), as shown in this answer from Mark Gravel:

 string returnValue = System.Convert.ToBase64String(toEncodeAsBytes) .TrimEnd(padding).Replace('+', '-').Replace('/', '_'); 

with:

 static readonly char[] padding = { '=' }; 

That is not all. If we take the Java output from

  Ye + fySvneVUZJXth67 + Si / e8fBUV4Sxs7wEXVDEOJjBMHl1encvt65gGIj8CiFzBGp5uUgKYJZCuQ4rc964vZigjlrJ / 430LgYcathLLd9U =

and decrypt it, then we get the following token:

  {"session_id": "4182e173-3a24-4c10-b76c-b85a36be1173", "ts_ms": 1445786965574}

which is different from the token you have in the code:

  {'session_id': 'abf52ca5-9d87-4061-b109-334abb7e637a', 'ts_ms': 1445705791480}

The main problem is that you are using invalid JSON. Strings and keys in JSON must be wrapped in " rather than ' .

This means that the encrypted token should have been (using a valid version of the token from your code):

  D9rOP07fYgBfza5vbGsvdPe8fBUV4Sxs7wEXVDEOJjBMHl1encvt65gGIj8CiFzBsAWBDgtdSozv4jS_auBU-CgjlrJ_430LgYcathLLd9U
+4
source

Here's a C # implementation that reproduces the same result as your Java code:

 class Program { public static byte[] GetKey(string siteSecret) { byte[] key = Encoding.UTF8.GetBytes(siteSecret); return SHA1.Create().ComputeHash(key).Take(16).ToArray(); } public static string EncryptAes(string input, string siteSecret) { var key = GetKey(siteSecret); using (var aes = AesManaged.Create()) { if (aes == null) return null; aes.Mode = CipherMode.ECB; aes.Padding = PaddingMode.PKCS7; aes.Key = key; byte[] inputBytes = Encoding.UTF8.GetBytes(input); var enc = aes.CreateEncryptor(key, new byte[16]); return UrlSafeBase64(enc.TransformFinalBlock(inputBytes,0,input.Length)); } } // http://stackoverflow.com/a/26354677/162671 public static string UrlSafeBase64(byte[] bytes) { return Convert.ToBase64String(bytes).TrimEnd('=') .Replace('+', '-') .Replace('/', '_'); } static void Main(string[] args) { string siteSecret = "12345678"; string jsonToken = "{'session_id':'abf52ca5-9d87-4061-b109-334abb7e637a','ts_ms':1445705791480}"; Console.WriteLine(" json token: " + jsonToken); Console.WriteLine(" siteSecret: " + siteSecret); Console.WriteLine(EncryptAes(jsonToken, siteSecret)); Console.ReadLine(); } } 

I don’t know why you said that you are getting Irez-rWkCEqnsiRLWfol0IXQu1JPs3qL_G_9HfUViMG9u4XhffHqAyju6SRvMhFS86czHX9s1tbzd6B15r1vmY6s5S8odXT-ZE9A-y1lHns which I get from Java because I get Irez-rWkCEqnsiRLWfol0IXQu1JPs3qL_G_9HfUViMG9u4XhffHqAyju6SRvMhFS86czHX9s1tbzd6B15r1vmY6s5S8odXT-ZE9A-y1lHns . The result that I get with both the C # version and the Java version is as follows:

Ye-fySvneVUZJXth67-Si_e8fBUV4Sxs7wEXVDEOJjBMHl1encvt65gGIj8CiFzBGp5uUgKYJZCuQ4rc964vZigjlrJ_430LgYcathLLd9U

As you can see here:

Screenshot with the exit of programs. The top is the C # version, and the bottom is the Java version (IntelliJ Idea 14.1.5)

The Java version has been copied / pasted from your code and uses guava-18.0 and compiled with JDK8 x64 (I am not a Java expert, so I just add them if that matters).

+3
source

Source: https://habr.com/ru/post/1234475/


All Articles