Генерация числа при шифровании строки - PullRequest
3 голосов
/ 14 апреля 2019

Я не специалист по шифрованию, но у меня есть требование сгенерировать число из входной строки и преобразовать его обратно в исходную строку.

Я много искал в интернете, но не смог найти никого, кто бы этим занимался. Поэтому я хотел бы получить помощь от экспертов по StackOverflow.

Насколько мне известно, шифрование строки в число немного сложнее, но проект, в котором я работаю, требует этого.

Любые библиотеки, которые делают это или любые алгоритмы, решат мою проблему.

Вот код, который у меня есть

import java.security.MessageDigest
import java.util
import javax.crypto.Cipher
import javax.crypto.spec.SecretKeySpec
import org.apache.commons.codec.binary.Base64


    object DataMaskUtil {

        def encrypt(key: String, value: String): String = {
          val cipher: Cipher = Cipher.getInstance("AES/ECB/PKCS5Padding")
          cipher.init(Cipher.ENCRYPT_MODE, keyToSpec(key))
           Base64.encodeBase64URLSafeString(cipher.doFinal(value.getBytes("UTF-8")))
        }

        def decrypt(key: String, encryptedValue: String): String = {
          val cipher: Cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING")
          cipher.init(Cipher.DECRYPT_MODE, keyToSpec(key))
          new String(cipher.doFinal(Base64.decodeBase64(encryptedValue)))
        }

        def keyToSpec(key: String): SecretKeySpec = {
          var keyBytes: Array[Byte] = (SALT + key).getBytes("UTF-8")
          val sha: MessageDigest = MessageDigest.getInstance("SHA-1")
          keyBytes = sha.digest(keyBytes)
          keyBytes = util.Arrays.copyOf(keyBytes, 16)
          new SecretKeySpec(keyBytes, "AES")
        }

         private val SALT: String =
        "jMhKlOuJnM34G6NHkqo9V010GhLAqOpF0BePojHgh1HgNg8^72k"

    }

Используя идею, предложенную Мартеном Бодевесом

object Util2 {

  def encrypt(value: String): BigInteger = {
    val ct = value.getBytes()
    val abyte = 0x4D.toByte
    val byteBuffer = ByteBuffer.allocate(2+ct.length)
    byteBuffer.put(abyte).put(abyte)
    byteBuffer.put(ct)
    val number = new BigInteger(byteBuffer.array())
    number
  }

  def decrypt(ctAsNumber: BigInteger): String = {
    if (ctAsNumber.signum < 0 || ctAsNumber.bitLength < 15) throw new IllegalArgumentException("Magic of ciphertext number doesn't match")
    import java.nio.ByteBuffer
    val fixed = ByteBuffer.allocate((ctAsNumber.bitLength + java.lang.Byte.SIZE - 1) / java.lang.Byte.SIZE)
    fixed.put(ctAsNumber.toByteArray)
    fixed.flip()
    val ct = new Array[Byte](fixed.remaining())
    fixed.get(ct)
    new String(ct)
  }
}

Когда я проверяю функции, вывод дополняется "ММ" перед строкой

object MainClass {

      def main(args: Array[String]): Unit ={
        val encrypt = Util2.encrypt("Hi")
        println("The encrypted string is :: "+encrypt)

        val decrypt = Util2.decrypt(encrypt)
        println("The decrypted string is :: "+decrypt)

      }

    }

выход

The encrypted string is :: 1296910441
The decrypted string is :: MMHi

1 Ответ

2 голосов
/ 16 апреля 2019

Конечно, есть несколько способов сделать это.Но давайте предположим, что нам нужны положительные значения (обычно требующиеся для криптографии), и что мы хотим, чтобы результат работал для ECB и CBC, а также, например, для шифрования в режиме CTR.В этом случае нам также нужно убедиться, что начальные нули обрабатываются изящно, потому что начальные нули имеют значение в зашифрованном тексте, но не для чисел.

И, так как это язык, работающий на JVM, мы будемиспользуйте также старший порядковый номер.

Отрицательных значений и нулевых байтов можно легко избежать, добавив битовые / байтовые значения в левую часть.Например, мы могли бы использовать общеизвестные значения, которые позволили бы вам иметь некоторую минимальную защиту от искажения числа зашифрованного текста.Тогда вы получите в Java:

private static BigInteger ciphertextToNumber(byte[] ct) {
    ByteBuffer fixed = ByteBuffer.allocate(2 + ct.length);
    fixed.put((byte) 0x4D).put((byte) 0x42);
    fixed.put(ct);
    BigInteger number = new BigInteger(fixed.array());
    return number;
}

private static byte[] numberToCiphertext(BigInteger ctAsNumber) {
    // if the number is negative then the buffer will be too small
    if (ctAsNumber.signum() < 0 || ctAsNumber.bitLength() < 15) {
        throw new IllegalArgumentException("Magic of ciphertext number doesn't match");
    }
    ByteBuffer fixed = ByteBuffer.allocate((ctAsNumber.bitLength() + Byte.SIZE - 1) / Byte.SIZE);
    fixed.put(ctAsNumber.toByteArray());
    fixed.flip();
    if (fixed.get() != (byte) 0x4D || fixed.get() != (byte) 0x42) {
        throw new IllegalArgumentException("Magic of ciphertext number doesn't match");
    }
    byte[] ct = new byte[fixed.remaining()];
    fixed.get(ct);
    return ct;
}

Это относительно эффективно и не увеличивает слишком большое возможное число по сравнению с зашифрованным текстом (так как зашифрованный текст может иметь любое значение байта, это, конечно,не возможно сжать это вместо этого).Одной из оптимизаций было бы извлечение байтовых значений магии непосредственно из BigInteger, но одна дополнительная копия зашифрованного текста, вероятно, не сильно повредит для такого рода целей.

Я оставлю это напреобразовать в Scala.


Другая идея состоит в том, чтобы использовать I2OSP или OS2IP, как определено в RFC RSA, но учтите, что заполнение RSA уже выполняет тот же вид заполнения слева, чтобы убедиться, что байтпреобразование массива в целое число обрабатывается изящно.Кроме того, зашифрованный текст RSA всегда имеет тот же размер, что и модуль, а шифрование AES может возвращать разные размеры.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...