Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Прочее";
Текущий архив: 2009.02.22;
Скачать: [xml.tar.bz2];

Вниз

Java & MS CryptoAPI   Найти похожие ветки 

 
Eraser ©   (2008-12-21 03:01) [0]

История такая. Имеется сервер и клиенты, все написано на Делфи. Канал связи между сервером и клиентом защищен с помощью RSA с использованием MS CryptoAPI.
Необходимо написать клиента к серверу на Java. Соответственно должно устанавливаться и RSA соединения, а потом и предача данных, зашифрованных симметричным алгоритмом.

Есть ли какие-либо готовые решения, для обеспечения совместимости ключей шифрования CryptoAPI <==> Java?


 
iZEN   (2008-12-21 17:47) [1]

JAAS


 
Eraser ©   (2008-12-22 03:08) [2]

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


 
Eraser ©   (2008-12-22 03:14) [3]

+ оказалось что Java не поддерживает 256 битные AES ключи. Точнее ключ генерирует, но когда доходит дело до шифрования им
      KeyGenerator kgen = KeyGenerator.getInstance("AES");
      kgen.init(256); // 192 and 256 bits may not be available (пример с сайта sun)

получаем
java.security.InvalidKeyException: Illegal key size or default parameters

но это известная проблема, посоветовали http://www.bouncycastle.org/java.html сейчас пробую как раз.


 
Eraser ©   (2008-12-22 18:17) [4]

проблему с 256 битными ключами решил, путем замены стандартной джававской криптобибилиотеки усиленной, которая не входит в стандартную поставку.

но проблема с ключем осталась. постараюсь подробнее изложить проблемный участок.

сервер (MS CryptoAPI) генерирует открытый и закрытый RSA ключи. отсылает клиенту (Java) открытый ключ.
клиент принимает ключ. на самом деле это не ключ в чистом виде, а Public Key BLOB, структуру которого можно посмотреть тут http://msdn.microsoft.com/en-us/library/aa387459(VS.85).aspx . В приниципе там все понятно. Выделяю из этого BLOB"а 4 байтную экспоненту и 256 байтный (2048bit) modulus. Реверсирую у обоих порядок байт, чтобы привеси их к виду BigIndian.

далее нужно сформировать симметричный ключ, а на основе его, т.к. Simple Key BLOB ( http://msdn.microsoft.com/en-us/library/aa387765(VS.85).aspx ). Генерирую симметричный ключ 256 битный AES ключ.
           // Генерируем AES ключ.
           int skLength = 256;
           KeyGenerator kgen = KeyGenerator.getInstance("AES");
           kgen.init(skLength);

           // Generate the secret key specs.
           SecretKey skey = kgen.generateKey();
           byte[] secretKeyData = skey.getEncoded();

далее компоную Simple Key BLOB, по точно такому алгоритму, как привел на ссылке.

но при отсылке этого ключа не сервере в функции CryptImportKey (которая импортирует симметричный ключ, расшифровывая его закрытым ключем) возникает ошибка NTE_BAD_FLAGS = HRESULT($80090009);

           // Формируем BLOB совместимый с MS CryptoAPI.
           // По материалам с http://msdn.microsoft.com/en-us/library/aa387765(VS.85).aspx

           /* Компонуем заголовок. */
           byte[] blobHeader = new byte[12];
           blobHeader[0] = 1; // The key is a session key.
           blobHeader[1] = 2; // Версия. Далее 2 байта не используются.
           // Идентификатор алгоритма (4 байта в перевернутом виде) CALG_AES_256 0x00006610.
           blobHeader[4] = (byte) 0x10;
           blobHeader[5] = (byte) 0x66;
           blobHeader[6] = 0;
           blobHeader[7] = 0;
           // Идентификатор алгоритма открытого RSA ключа, котором зашифрован данный ключ.
           blobHeader[8] = 0;
           blobHeader[9] = (byte) 0xA4;
           blobHeader[10] = 0;
           blobHeader[11] = 0;

           // Компонуем PKCS #1 блок, раный по размеру длине открытого ключа.
           int pubKeySize = 256;
           byte[] blobPKCS = new byte[pubKeySize];
           blobPKCS[0] = 0; // Ноль.
           blobPKCS[1] = 0x02; // The PKCS block type (0x02).
           // Вычисляем длину заполнителя.
           int paddingSize = pubKeySize - 2 - (skLength / 8) - 1;
           int paddingStart = 3;
           int j = 0;
           // Заполняем случайными данными.
           for (int i = 0; i < paddingSize; i++) {
               // Реальный индекс элемента.
               j = paddingStart + i;

               // Заполняем случайным значением.
               //blobPKCS[j] = 0;
               blobPKCS[j] = (byte) ROMRandom.randomRange(1, 255);
           }
           // Ноль.
           blobPKCS[paddingStart + paddingSize] = 0;
           // Начало ключа.
           int keyStart = paddingStart + paddingSize;

           //secretKeyData[secretKeyData.length - 2] = 77;
           //secretKeyData = reverseArray(secretKeyData);

           // Копируем данные ключа.
           for (int i = 0; i < secretKeyData.length; i++) {
               // Индекс в PKCS блоке.
               j = keyStart + i;
               blobPKCS[j] = secretKeyData[i];
           }
           writeKeyBytesToFile(blobPKCS, "d:\\java_raw_PKCS.dat");
           // Реверсируем PKCS.
           //blobPKCS = reverseArray(blobPKCS); // !!!

           // Зашифруем PKCS открытым ключем.
           BigInteger data = new BigInteger(
                   1,
                   blobPKCS);

           // Perform RSA encryption:
           // ciphertext = plaintext^exponent % modulus.
           BigInteger cipherText = data.modPow(
                   exponent,
                   modulus);

           // Reverse the generated ciphertext.
           byte[] encryptedPKCS = cipherText.toByteArray();
           encryptedPKCS = reverseArray(encryptedPKCS); // !!!
           writeKeyBytesToFile(encryptedPKCS, "d:\\java_enc_PKCS.dat");

           //encryptedPKCS[encryptedPKCS.length - 5] = 77;

           // Объединим заголовок и зашифрованный PKCS.
           byte[] fullSecretKeyData = new byte[blobHeader.length + encryptedPKCS.length];

           for (int i = 0; i < blobHeader.length; i++) {
               fullSecretKeyData[i] = blobHeader[i];
           }

           for (int i = 0; i < encryptedPKCS.length; i++) {
               fullSecretKeyData[blobHeader.length + i] = encryptedPKCS[i];
           }

           writeKeyBytesToFile(fullSecretKeyData, "d:\\java_secret_simpleblob.dat");
// Далее идет код отсылки на сервер

не могу понят на каком этапе формирования Simple Key BLOB я допустил промах. очевидно, что данные открытым ключем шифрую правильно. Т.к. если в заголовок encryptedPKCS вписать какую нибудь ерунду, то сервер выдает соответсвующую ошибку.
пробовал вместо самостоятельной генерации секретного ключа, подставлять ключ, сгенерированный через CryptoAPI - эффекта нет. но оно и правильно, т.к. ключ это просто набор случайных данных по-сути.
в общем в тупике пока что...


 
Eraser ©   (2008-12-22 20:51) [5]

проблема решена, немного не правильно формировал Simple Key BLOB.
Вот корректный кусок кода для связки (RSA 2048 + AES 256):
           // Обмен ключами.
           // Размер открытого ключа.
           int iSize = input.readInt();
           byte[] publicKeyData = new byte[iSize];

           input.read(publicKeyData, 0, iSize);

           // Экспонента ключа.
           int exponentStart = 8 + 4 + 4;
           byte[] exponentBytes = Arrays.copyOfRange(publicKeyData,
                   exponentStart, exponentStart + 4);

           //writeKeyBytesToFile(exponentBytes, "d:\\java_pkey_exponent.dat");
           exponentBytes = reverseArray(exponentBytes);
           BigInteger exponent = new BigInteger(1, exponentBytes);
           //System.out.println("exponent: " + exponent);

           // Modulus ключа.
           int modulusStart = 8 + 12;
           byte[] modulusBytes = Arrays.copyOfRange(publicKeyData,
                   modulusStart, publicKeyData.length);

           //writeKeyBytesToFile(modulusBytes, "d:\\java_pkey_modulus.dat");
           modulusBytes = reverseArray(modulusBytes);
           BigInteger modulus = new BigInteger(1, modulusBytes);

           //System.out.println("modulus length: " + modulusBytes.length);
           //writeKeyBytesToFile(publicKeyData, "d:\\java_pkey.dat");

           // Генерируем AES ключ.
           int skLength = 256;
           KeyGenerator kgen = KeyGenerator.getInstance("AES");
           kgen.init(skLength);

           // Generate the secret key specs.
           SecretKey skey = kgen.generateKey();
           byte[] secretKeyData = skey.getEncoded();
           //writeKeyBytesToFile(secretKeyData, "d:\\java_secret_aes256.dat");

           // Формируем BLOB совместимый с MS CryptoAPI.
           // По материалам с http://msdn.microsoft.com/en-us/library/aa387765(VS.85).aspx

           // Компонуем заголовок.
           byte[] blobHeader = new byte[12];
           blobHeader[0] = 1; // The key is a session key.
           blobHeader[1] = 2; // Версия. Далее 2 байта не используются.
           // Идентификатор алгоритма (4 байта в перевернутом виде) CALG_AES_256 0x00006610.
           blobHeader[4] = (byte) 0x10;
           blobHeader[5] = (byte) 0x66;
           blobHeader[6] = 0;
           blobHeader[7] = 0;
           // Идентификатор алгоритма открытого RSA ключа, котором зашифрован данный ключ.
           blobHeader[8] = 0;
           blobHeader[9] = (byte) 0xA4;
           blobHeader[10] = 0;
           blobHeader[11] = 0;

           // Компонуем PKCS #1 блок, раный по размеру длине открытого ключа.
           int pubKeySize = 256;
           byte[] blobPKCS = new byte[pubKeySize];
           blobPKCS[0] = 0; // Ноль.
           blobPKCS[1] = 0x02; // The PKCS block type (0x02).
     
           // Вычисляем длину заполнителя.
           int paddingSize = pubKeySize - 2 - (skLength / 8) - 1;
           int paddingStart = 2;
           int j = 0;
           // Заполняем случайными данными.
           for (int i = 0; i < paddingSize; i++) {
               // Реальный индекс элемента.
               j = paddingStart + i;

               // Заполняем случайным значением.
               blobPKCS[j] = (byte) ROMRandom.randomRange(1, 255);
           }
           // Ноль.
           blobPKCS[paddingStart + paddingSize] = 0;
           // Начало ключа.
           int keyStart = paddingStart + paddingSize + 1;

           // Копируем данные ключа.
           for (int i = 0; i < secretKeyData.length; i++) {
               // Индекс в PKCS блоке.
               j = keyStart + i;
               blobPKCS[j] = secretKeyData[i];
           }

           blobPKCS = reverseArray(blobPKCS);
           //writeKeyBytesToFile(blobPKCS, "d:\\java_raw_PKCS.dat");
           
           // Реверсируем PKCS.
           blobPKCS = reverseArray(blobPKCS); // !!!

           // Зашифруем PKCS открытым ключем.
           // http://msdn.microsoft.com/en-us/library/cc240810(PROT.10).aspx
           BigInteger data = new BigInteger(
                   1,
                   blobPKCS);

           // Perform RSA encryption:
           // ciphertext = plaintext^exponent % modulus.
           BigInteger cipherText = data.modPow(
                   exponent,
                   modulus);

           // Reverse the generated ciphertext.
           byte[] encryptedPKCS = cipherText.toByteArray();
           encryptedPKCS = reverseArray(encryptedPKCS); // !!!
           //writeKeyBytesToFile(encryptedPKCS, "d:\\java_enc_PKCS.dat");

           // Объединим заголовок и зашифрованный PKCS.
           byte[] fullSecretKeyData = new byte[blobHeader.length + encryptedPKCS.length];

           for (int i = 0; i < blobHeader.length; i++) {
               fullSecretKeyData[i] = blobHeader[i];
           }

           for (int i = 0; i < encryptedPKCS.length; i++) {
               fullSecretKeyData[blobHeader.length + i] = encryptedPKCS[i];
           }

           //writeKeyBytesToFile(fullSecretKeyData, "d:\\java_secret_simpleblob.dat");

           // Отсылаем симметричный ключ.
           output.writeInt(fullSecretKeyData.length);
           output.write(fullSecretKeyData);

           // Считываем тип авторизации.
           int iAuthKind = input.readInt();
           if (iAuthKind != 1) {
               // Поддерживается только авторизация паролем.
               return;
           }

           // Зашифруем пароль симметричным ключем.
           byte[] passwordData = fConnection.getPassword().getBytes();
           SecretKeySpec skeySpec = new SecretKeySpec(secretKeyData, "AES");

           Cipher cipher = Cipher.getInstance("AES");
           cipher.init(Cipher.ENCRYPT_MODE, skeySpec);

           byte[] encrypted =
                   cipher.doFinal(passwordData);
           
           // Отсылаем зашированный пароль.
           output.writeInt(encrypted.length);
           output.write(encrypted);
           
           // Правильный или нет пароль.
           boolean passwordCorrect = input.readInt() == 1;

           System.out.println("password state: " + passwordCorrect);
           System.out.println("finished!");



Страницы: 1 вся ветка

Форум: "Прочее";
Текущий архив: 2009.02.22;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.52 MB
Время: 0.009 c
9-1177433968
@!!ex
2007-04-24 20:59
2009.02.22
ПРоблемы Z буффера.


2-1231927823
smartleds
2009-01-14 13:10
2009.02.22
Уважаемый All, есть процедура FormCreate поясните как


9-1177264606
ElectriC
2007-04-22 21:56
2009.02.22
Класс тени в DirectX


15-1230323029
Kerk
2008-12-26 23:23
2009.02.22
Отмечание нового года


4-1203884779
art36
2008-02-24 23:26
2009.02.22
устройство веб камеры + видео поток + delphi





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский