Java到Objective-C RSA的实现

我在Objective-C中实现RSA encryption和解密时遇到了麻烦,我用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我写了一些sems工作的代码,但我不知道从种子生成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; } 

正如我在其他答案中解释的那样,使用相同的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 eg RSA key pair generation 

似乎没有方法在Apple的OS X库中注入您自己的随机数生成器。 如图所示,通常操作系统提供的随机数生成器就足够了。 如果你真的想要,可以将你的额外种子写入/dev/random

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

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

有关更多信息,请参阅此Q / A. 不要忘记在那里投票问答,我可以在加密上使用更多点:)。