Генерация стокен (конвертирование из Java в Ruby)

Google предоставил следующий пример кода, показывающий, как сгенерировать безопасный токен для своей второй версии Recaptcha:

public class STokenUtils {
  private static final String CIPHER_INSTANCE_NAME = "AES/ECB/PKCS5Padding";

  public static final String createSToken(String siteSecret) {
    String sessionId = UUID.randomUUID().toString();
    String jsonToken = createJsonToken(sessionId);
    return encryptAes(jsonToken, siteSecret);
  }

  private static final String createJsonToken(String sessionId) {
    JsonObject obj = new JsonObject();
    obj.addProperty("session_id", sessionId);
    obj.addProperty("ts_ms", System.currentTimeMillis());
    return new Gson().toJson(obj);
  }

  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 String decryptAes(String input, String key) throws Exception {
    SecretKeySpec secretKey = getKey(key);
    Cipher cipher = Cipher.getInstance(CIPHER_INSTANCE_NAME);
    cipher.init(Cipher.DECRYPT_MODE, secretKey);
    return new String(cipher.doFinal(
        BaseEncoding.base64Url().omitPadding().decode(input)), "UTF-8");
  }

  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;
  }
}

Полный код можно найти по адресу: https://github.com/google/recaptcha-java

Я хочу сгенерировать этот токен в Ruby 2.1+ и зашел так далеко, но он выводит неверные данные. Я пытаюсь медленно отладить его, но в то же время мне интересно, может ли кто-нибудь увидеть какие-либо очевидные недостатки в моем процессе?

      stoken_json = hash_to_json({'session_id' => SecureRandom.uuid, 'ts_ms' => Time.now.to_i})
      cipher = OpenSSL::Cipher::AES128.new(:ECB)
      private_key_digest = Digest::SHA1.hexdigest(private_key)[0...16]    

      cipher.encrypt
      cipher.key = private_key_digest
      encrypted_stoken = cipher.update(stoken_json) << cipher.final
      encoded_stoken = Base64.urlsafe_encode64(encrypted_stoken).gsub(/\=+\Z/, '')

1 ответ

Решение

Оказывается, я был близко. я нуждался в digest не hexdigest закрытый ключ:

private_key_digest = Digest::SHA1.digest(private_key)[0...16]

Итак, окончательный код:

stoken_json = hash_to_json({'session_id' => SecureRandom.uuid, 'ts_ms' => (Time.now.to_f * 1000).to_i})
cipher = OpenSSL::Cipher::AES128.new(:ECB)
private_key_digest = Digest::SHA1.digest(private_key)[0...16]

cipher.encrypt
cipher.key = private_key_digest
encrypted_stoken = cipher.update(stoken_json) << cipher.final
encoded_stoken = Base64.urlsafe_encode64(encrypted_stoken).gsub(/\=+\Z/, '')

Кажется, не было встроенного способа убрать отступы из строки base64, поэтому .gsub в конце.

Мне также понадобилась метка времени в миллисекундах, чтобы часть тоже была изменена.

В геме рекапчи есть метод hash_to_json что я использую, в противном случае я подозреваю, что вы будете использовать драгоценный камень JSON.

Другие вопросы по тегам