【问题标题】:Java to Objective-C RSA ImplementationJava 到 Objective-C RSA 的实现
【发布时间】:2014-08-12 00:06:38
【问题描述】:

我在实现RSA encryptionObjective-C 中的解密时遇到了麻烦,我非常简单地在Java 中实现了它,现在我尝试在objc 中翻译这个java 代码。 这是我的java 代码:

public static byte[] encryptRSA(byte[] text, PublicKey key) throws Exception {

byte[] cipherText = null;
// get an RSA cipher object and print the provider
Cipher cipher = Cipher.getInstance("RSA");

// encrypt the plaintext using the public key
cipher.init(Cipher.ENCRYPT_MODE, key);
cipherText = cipher.doFinal(text);
return cipherText;

}

public static byte[] decryptRSA(byte[] text, PrivateKey key) throws Exception {

byte[] dectyptedText = null;
// decrypt the text using the private key
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, key);
dectyptedText = cipher.doFinal(text);
return dectyptedText;

}

这就是我生成密钥对的方式

    String seed = "SOMERANDOMSEED"+Long.toString(System.currentTimeMillis());
    KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
    SecureRandom rand = new SecureRandom(seed.getBytes());

    keyGen.initialize(4096,rand);


    KeyPair keyPair = keyGen.generateKeyPair();
    PrivateKey privateKey = keyPair.getPrivate();
    PublicKey publicKey = keyPair.getPublic();

现在在 objC 中,我编写了一些似乎可以工作的代码,但我不知道如何从种子中生成 rsa,就像我在 java 中所做的那样,以及如何导入我在 java 中保存的密钥这个方法

   //for import
   public static byte[] hexStringToByteArray(String s) {
        byte[] b = new byte[s.length() / 2];
        for (int i = 0; i < b.length; i++) {
            int index = i * 2;
            int v = Integer.parseInt(s.substring(index, index + 2), 16);
            b[i] = (byte) v;
        }
        return b;
    }



//for export 
    public static String byteArrayToHexString(byte[] b) {
    StringBuilder sb = new StringBuilder(b.length * 2);
    for (int i = 0; i < b.length; i++) {
        int v = b[i] & 0xff;
        if (v < 16) {
            sb.append('0');
        }
        sb.append(Integer.toHexString(v));
    }
    return sb.toString().toUpperCase();
}

这是我的 objc 代码

//this works properly
+(NSString *)decryptRSA:(NSString *)cipherString key:(SecKeyRef) privateKey {
    size_t plainBufferSize = SecKeyGetBlockSize(privateKey);
    uint8_t *plainBuffer = malloc(plainBufferSize);
    NSData *incomingData = [cipherString decodeFromHexidecimal];
    uint8_t *cipherBuffer = (uint8_t*)[incomingData bytes];
    size_t cipherBufferSize = SecKeyGetBlockSize(privateKey);
    SecKeyDecrypt(privateKey,
                  kSecPaddingOAEPKey,
                  cipherBuffer,
                  cipherBufferSize,
                  plainBuffer,
                  &plainBufferSize);
    NSData *decryptedData = [NSData dataWithBytes:plainBuffer length:plainBufferSize];
    NSString *decryptedString = [[NSString alloc] initWithData:decryptedData encoding:NSUTF8StringEncoding];
    return decryptedString;
}
//this works properly
+(NSString *)encryptRSA:(NSString *)plainTextString key:(SecKeyRef)publicKey {
    size_t cipherBufferSize = SecKeyGetBlockSize(publicKey);
    uint8_t *cipherBuffer = malloc(cipherBufferSize);
    uint8_t *nonce = (uint8_t *)[plainTextString UTF8String];
    SecKeyEncrypt(publicKey,
                  kSecPaddingOAEPKey,
                  nonce,
                  strlen( (char*)nonce ),
                  &cipherBuffer[0],
                  &cipherBufferSize);
    NSData *encryptedData = [NSData dataWithBytes:cipherBuffer length:cipherBufferSize];

    return [encryptedData hexadecimalString];
}
//here i generate the key pair
#define kPublicKeyTag           "com.apple.sample.publickey"
#define kPrivateKeyTag          "com.apple.sample.privatekey"
//i should use these as seed!?!!?
- (void)generateKeyPair:(NSUInteger)keySize {
    OSStatus sanityCheck = noErr;
    publicKeyRef = NULL;
    privateKeyRef = NULL;


    // Container dictionaries.
    NSMutableDictionary * privateKeyAttr = [[NSMutableDictionary alloc] init];
    NSMutableDictionary * publicKeyAttr = [[NSMutableDictionary alloc] init];
    NSMutableDictionary * keyPairAttr = [[NSMutableDictionary alloc] init];

    // Set top level dictionary for the keypair.
    [keyPairAttr setObject:(id)kSecAttrKeyTypeRSA forKey:(id)kSecAttrKeyType];
    [keyPairAttr setObject:[NSNumber numberWithUnsignedInteger:keySize] forKey:(id)kSecAttrKeySizeInBits];

    // Set the private key dictionary.
    [privateKeyAttr setObject:[NSNumber numberWithBool:YES] forKey:(id)kSecAttrIsPermanent];
    [privateKeyAttr setObject:privateTag forKey:(id)kSecAttrApplicationTag];
    // See SecKey.h to set other flag values.

    // Set the public key dictionary.
    [publicKeyAttr setObject:[NSNumber numberWithBool:YES] forKey:(id)kSecAttrIsPermanent];
    [publicKeyAttr setObject:publicTag forKey:(id)kSecAttrApplicationTag];
    // See SecKey.h to set other flag values.

    // Set attributes to top level dictionary.
    [keyPairAttr setObject:privateKeyAttr forKey:(id)@kSecPrivateKeyAttrs];
    [keyPairAttr setObject:publicKeyAttr forKey:(id)@kSecPublicKeyAttrs];

    // SecKeyGeneratePair returns the SecKeyRefs just for educational purposes.
    sanityCheck = SecKeyGeneratePair((__bridge CFDictionaryRef)keyPairAttr, &publicKeyRef, &privateKeyRef);


}

这是我在 objc 中导出密钥的方法,它看起来就像 java 方法一样工作

+ (NSString *)fromPrivateKeyToString: (SecKeyRef) privateKey {
    size_t pkeySize = SecKeyGetBlockSize(privateKey);
    NSData* pkeyData = [NSData dataWithBytes:privateKey length:pkeySize];
    NSString* pkeyString = [pkeyData hexadecimalString];

    return pkeyString;

}

【问题讨论】:

  • 问题出在哪里?
  • 我不知道如何从 NSData 生成 SecKeyRef,以及如何像在 Java 中一样从随机种子生成 Objective-C 中的 KeyPair。有什么建议吗?
  • 好的,所以我可能误解了。因此,如果我错了,请纠正我:您想仅使用您的随机种子和当前时间(以毫秒为单位)创建一个随机密钥对,但您没有这样做,因为您想在稍后阶段重复该过程以创建确切的相同的密钥对?你这样做只是为了随机数生成器的种子吗?

标签: java objective-c encryption rsa public-key-encryption


【解决方案1】:

正如我在其他答案中所解释的,使用相同的 PRNG 值生成相同的密钥对非常棘手。但这似乎不是你所追求的。看来您想使用自己的种子 PRNG 来生成密钥对。


一般来说,Java 中默认的SecureRandom 是由操作系统播种的。您可以提供自己的随机数生成器的想法是,您可以使用例如您自己的熵池(例如来自硬件随机数生成器)获得“更好”的结果。但是,通常由操作系统播种的默认 Java PRNG 会提供足够的随机性。

当您使用SecureRandom 类时,您取代操作系统为种子提供了您自己相对较弱的种子PRNG。 currentTimeMilis 当然不会给你太多熵,而且密码似乎是静态的。通常认为这不足以生成 RSA 密钥对。

如果你真的愿意,你可以添加一些熵到池中:

// create runtime default PRNG
SecureRandom rng = new SecureRandom();
// make sure that the rng is seeded by the operating system
rng.nextInt();
// add secret to the pool
rng.setSeed("SOME_SECRET".getBytes(StandardCharsets.UTF_8));
// add time information to the pool
rng.setSeed(System.currentTimeMillis());
// use for e.g. RSA key pair generation

似乎没有办法在 Apple 的 OS X 库中注入您自己的随机数生成器。如前所述,通常操作系统提供的随机数生成器就足够了。如果你真的想你可以write your additional seeds to /dev/random though

【讨论】:

    【解决方案2】:

    虽然不可能从种子中创建相同的密钥对,但您需要确保 RNG 生成的密钥对完全相同。此外,需要以相同的方式使用要放入生成器中的种子。创建 RNG 或密钥对生成通常都没有考虑到兼容性。实际上,默认的“SHA1PRNG”甚至在Java版本之间都有变化,算法没有描述。

    如果您想使用相同的私钥,那么最好生成它并将其传输到其他运行时。有多种方法,但一种方法是使用(密码)加密的 PKCS#8 或 PKCS#12 格式。当然,密钥或密码需要保密,但您的种子值也是如此。

    有关详细信息,请参阅this Q/A。别忘了在那边给问题和答案投票,我可以在加密上多加点:)。

    【讨论】:

    • 我不需要生成相同的密钥对,而是从“密码”+RNG 等类似的种子生成它,然后将公钥导出到另一个运行时(在 Java 中我翻译byte[] 转换为 String,我在 ObjC 中也这样做,但在 ObjC 中我不知道如何将 NSData 对象转换为公钥的 SecKeyRef 对象),广告使用它来加密,私钥留在运行时生成它。感谢您的回答(ps 我不能投票我没有足够的声誉)
    • 好吧,我也不能再投票了 :) 如果您只想使用随机输入生成密钥,您应该使用 new SecureRandom() 而不是提供种子。默认情况下,Java RE 将从操作系统中获取一个随机值,这比getCurrentTimeMilis() 或其他任何东西要好得多。如果您想使用额外的随机数据,则首先从rand 获取一些字节,然后使用setSeed() 添加时间和秘密种子(实际上将给定信息添加到随机池中)。
    猜你喜欢
    • 2012-04-30
    • 1970-01-01
    • 2013-04-10
    • 1970-01-01
    • 1970-01-01
    • 2014-06-27
    • 2010-09-27
    • 2011-02-23
    相关资源
    最近更新 更多