【问题标题】:Getting 1 byte extra in the modulus RSA Key and sometimes for exponents also在模数 RSA 密钥中额外获得 1 个字节,有时也为指数
【发布时间】:2012-01-20 21:20:32
【问题描述】:

这是我的代码 sn-p:

 int eValue = 79, t;
 int bitLength = 1024; // KeySize
 BigInteger e = new BigInteger(Integer.toString(eValue));
 KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
 kpg.initialize(bitLength);
 KeyPair kp = kpg.generateKeyPair();
 KeyFactory kfactory = KeyFactory.getInstance("RSA");
 RSAPublicKeySpec kspec = (RSAPublicKeySpec) kfactory.getKeySpec(kp.getPublic(),
 RSAPublicKeySpec.class);
 System.out.println("Byte Length is : " + kspec.getModulus().toByteArray().length);
 String testString;
   try {
        testString = new String (kspec.getModulus().toByteArray() , "ISO-8859-1");
        StringBuilder tt  = new StringBuilder();
        for(t =0 ; t< testString.length() ; t++)
            {
                tt.append((int) testString.charAt(t)+",");
            }
            String encryptedBytes = tt.toString();
        System.out.println("Mod is : " + encryptedBytes);
    }catch (Exception ex) {
            // TODO: handle exception
 }

这是输出:

Byte Length is : 129
Mod is : 0,190,193,141,230,128,124,6,201,254,135,66,162,65,147,160,76,160,181,7,141,113,8,57,193,185,206,42,125,9,169,209,124,74,233,151,10,128,180,35,24,206,213,32,48,4,39,178,60,10,249,151,50,218,220,11,124,72,64,148,135,251,133,23,54,171,25,202,157,28,21,39,239,234,48,56,79,36,127,59,203,108,189,232,216,231,237,237,90,253,19,118,29,18,142,126,254,193,189,82,15,126,139,136,45,31,133,242,187,81,62,52,5,23,11,217,171,233,7,137,115,30,93,206,236,31,196,111,153

对于 1024 位长度的密钥模数应该是 128 字节,对于 2048 应该是 256,但是我得到了一个额外的字节(总是在第一个字节添加 0),需要帮助来解决这个问题..

谢谢, 帕万

【问题讨论】:

标签: java android cryptography rsa key-generator


【解决方案1】:

开始时 00h 值字节的原因是因为 BigInteger.toByteArray() 返回有符号表示。只要以位为单位的密钥长度为 N*8(或密钥长度 % 8 = 0),那么 RSA 模数的带符号表示将始终在开头具有 00h 值的字节。

如果初始字节为零,只需将其复制到以字节为单位的密钥长度数组中即可。请注意,如果您有一个私有指数,它也可能 比密钥长度(以字节为单位),因此将其复制到新字节数组的末尾。通常,这种方法称为 I2OS 或 I2O(整数到八位字节字符串),其中八位字节字符串(java 中的字节数组)具有指定的长度。

/**
 * Encodes the given value as a unsigned Big Endian within an octet string
 * of octetStringSize bytes.
 * 
 * @param i
 *            the integer to encode
 * @param octetStringSize
 *            the number of octets in the octetString returned
 * @return the encoding of i
 * @throws IllegalArgumentException
 *             if the given integer i is negative
 * @throws IllegalArgumentException
 *             if the octetStringSize is zero or lower
 * @throws IllegalArgumentException
 *             if the given BigInteger does not fit into octetStringSize
 *             bytes
 */
public static byte[] integerToOctetString(final BigInteger i,
        final int octetStringSize) {

    // throws NullPointerException if i = null
    if (i.signum() < 0) {
        throw new IllegalArgumentException(
                "argument i should not be negative");
    }

    if (octetStringSize <= 0) {
        throw new IllegalArgumentException("octetStringSize argument ("
                + octetStringSize
                + ") should be higher than 0 to store any integer");
    }

    if (i.bitLength() > octetStringSize * Byte.SIZE) {
        throw new IllegalArgumentException("argument i (" + i
                + ") does not fit into " + octetStringSize + " octets");
    }

    final byte[] signedEncoding = i.toByteArray();
    final int signedEncodingLength = signedEncoding.length;

    if (signedEncodingLength == octetStringSize) {
        return signedEncoding;
    }

    final byte[] unsignedEncoding = new byte[octetStringSize];
    if (signedEncoding[0] == (byte) 0x00) {
        // skip first padding byte to create a (possitive) unsigned encoding for this number 
        System.arraycopy(signedEncoding, 1, unsignedEncoding,
                octetStringSize - signedEncodingLength + 1,
                signedEncodingLength - 1);

    } else {
        System.arraycopy(signedEncoding, 0, unsignedEncoding,
                octetStringSize - signedEncodingLength,
                signedEncodingLength);
    }
    return unsignedEncoding;
}

/**
 * Returns a BigInteger that is the value represented by the unsigned, Big
 * Endian encoding within the given octetString.
 * 
 * @param octetString
 *            the octetString containing (only) the encoding
 * @return the value represented by the octetString
 */
public static BigInteger octetStringToInteger(final byte[] octetString) {
    // arguments are signum, magnitude as unsigned, Big Endian encoding
    return new BigInteger(1, octetString);
}

/**
 * Returns the minimum number of bytes required to directly store the given
 * number of bits.
 * 
 * @param bitSize
 *            the bitSize
 * @return the size as a number of bytes
 * @throws IllegalArgumentException
 *             if the given bitSize argument is negative
 */
public static int bitSizeToByteSize(final int bitSize) {
    if (bitSize < 0) {
        throw new IllegalArgumentException("bitSize (" + bitSize
                + " should not be negative");
    }

    return (bitSize + Byte.SIZE - 1) / Byte.SIZE;
}

【讨论】:

  • PS 还没有对给定的方法进行单元测试,但根据“好”的场景应该没问题
【解决方案2】:

您可以使用 Arrays.deepToString() 直接打印一个字节数组:

String encryptedBytes = Arrays.deepToString(new Object[] { kspec.getModulus().toByteArray() })

我怀疑您在处理有符号数字和无符号数字时遇到了问题。 128 位模数是无符号的,但将其存储在 BigInteger 中有时可能需要 129 位,因此需要额外的字节。

【讨论】:

  • 嗯,我自己总是使用 toHex 辅助方法,它使用字节数组长度乘以 2 的 StringBuilder,然后为每个字节使用 sb.append(String.format("%02X")) .我认为十六进制更有用。
  • 你说得对,十六进制更好。当然,总会有 commons-codec 的Hex.encodeHexString
  • 它只打印到 127,大于 128 它打印 -ve 数字,如果第一个字节为 128 或更大,则为 0。
  • 执行 & 0xFF 以获得具有正确值的正整数,例如String.format("%02X", data[i] & 0xFF)...抱歉。
【解决方案3】:

正如 Maarten Bodewes 所回答的,额外的字节是BigInteger 符号的空间。

如果预期的大小是已知的并且十六进制是可以接受的,我会使用这样的:

System.out.printf("Mod is : %0256x%n" , kspec.getModulus());

【讨论】:

    【解决方案4】:

    这个问题最好在下面的 Stackoverflow 链接中回答。该解决方案也非常简单,适用于所有加密应用程序,因为所有加密密钥的长度都是 8 的精确倍数。

    BigInteger to byte[]

    【讨论】:

      猜你喜欢
      • 2014-04-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-21
      • 1970-01-01
      • 2020-01-25
      • 1970-01-01
      • 2015-10-13
      相关资源
      最近更新 更多