Реализация Java в Objective-C RSA

1

У меня возникли проблемы с внедрением RSA encryption и расшифровки в Objective-C, я сделал это в Java очень просто, и теперь я попытался перевести этот java код в objc. Вот мой код 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;

}
  • 0
    И в чем проблема?
  • 0
    Я не знаю, как сгенерировать SecKeyRef из NSData и как сгенерировать KeyPair в Objective-C из случайного начального числа, как я это делаю в Java. Какие-либо предложения?
Показать ещё 1 комментарий
Теги:
encryption
rsa
public-key-encryption

2 ответа

0
Лучший ответ

Как я объяснил в своем другом ответе, очень сложно создать ту же пару ключей, используя то же значение PRNG. Но это не похоже на то, что вам нужно. Кажется, что вы хотите использовать свой собственный сеянный PRNG для генерации пары ключей.


В общем случае по умолчанию SecureRandom в Java засевается операционной системой. Идея, что вы можете предоставить свой собственный генератор случайных чисел, состоит в том, что вы можете получить "лучшие" результаты, используя, например, собственный пул энтропий (например, от генератора случайных чисел оборудования). Обычно стандартная 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. Как указано, обычно ОС обеспечивает генератор случайных чисел. Если вы действительно хотите, чтобы вы могли написать свои дополнительные семена в /dev/random хотя.

1

Хотя создание одной и той же пары ключей из семени невозможно, вам нужно убедиться, что генерация RNG и пары ключей идентична. Кроме того, семена, которые должны быть помещены в генератор, должны использоваться одинаково. Ни генерация RNG, ни генерация ключей обычно не создаются с учетом совместимости. Фактически, по умолчанию "SHA1PRNG" даже изменился между версиями Java, и алгоритм не описан.

Если вы хотите использовать один и тот же закрытый ключ, лучше создать его и перенести его в другую среду выполнения. Существует несколько способов, но один метод заключается в использовании шифрованного PKCS # 8 или PKCS # 12 (пароля). Конечно, ключ или пароль должны храниться в секрете, но это также случай с вашим значением семени.

Для получения дополнительной информации см. Этот вопрос. Не забудьте проголосовать за вопрос и ответить там, я могу использовать еще несколько баллов по криптому :).

  • 0
    Мне не нужно генерировать ту же пару ключей, но генерировать ее из аналогичного начального числа, такого как «пароль» + RNG, а затем экспортировать открытый ключ в другое время выполнения (в Java я преобразую byte [] в String, я делаю то же самое в ObjC, но в ObjC я не знаю, как преобразовать объект NSData в объект SecKeyRef для открытого ключа), и используем его для шифрования, закрытый ключ остается во время выполнения, которое его генерирует. Спасибо за ответ (ps я не могу проголосовать, мне не хватает репутации)
  • 0
    Ну, я тоже не могу голосовать больше :) Если вы просто хотите, чтобы ключ генерировался с использованием случайного ввода, вы должны использовать new SecureRandom() вместо предоставления начального числа. По умолчанию Java RE будет принимать случайное значение из операционной системы, что намного лучше, чем getCurrentTimeMilis() или что-либо еще. Если вы хотите использовать дополнительные случайные данные, то сначала получите несколько байтов от rand , затем добавьте время и секретное начальное число с помощью setSeed() (который фактически добавляет данную информацию в случайный пул).

Ещё вопросы

Сообщество Overcoder
Наверх
Меню