سؤال

لدي وحدة C++ قديمة توفر التشفير/فك التشفير باستخدام مكتبة opensl (تشفير DES).أحاول ترجمة هذا الرمز إلى جافا، ولا أريد الاعتماد على DLL، JNI، وما إلى ذلك ...يبدو رمز C++ كما يلي:

des_string_to_key(reinterpret_cast<const char *>(key1), &initkey);
des_string_to_key(reinterpret_cast<const char *>(key2), &key);
key_sched(&key, ks);
// ...
des_ncbc_encrypt(reinterpret_cast<const unsigned char *>(tmp.c_str()), 
reinterpret_cast< unsigned char *>(encrypted_buffer), tmp.length(), ks, &initkey, 
DES_ENCRYPT);

return base64(reinterpret_cast<const unsigned char *>(encrypted_buffer),    strlen(encrypted_buffer));

يبدو كود جافا كما يلي:

Cipher ecipher;
try {
    ecipher = Cipher.getInstance("DES");
    SecretKeySpec keySpec = new SecretKeySpec(key, "DES");      
    ecipher.init(Cipher.ENCRYPT_MODE, keySpec);         
    byte[] utf8 = password.getBytes("UTF8");
    byte[] enc = ecipher.doFinal(utf8);
    return new sun.misc.BASE64Encoder().encode(enc);
}
catch {
    // ...
}

لذا يمكنني إجراء تشفير DES في Java بسهولة تامة، ولكن كيف يمكنني الحصول على نفس النتيجة كما هو الحال مع الكود أعلاه بطرق مختلفة تمامًا؟ما يزعجني على وجه الخصوص هو حقيقة أن إصدار C++ يستخدم مفتاحين بينما يستخدم إصدار Java مفتاحًا واحدًا فقط.الإجابة حول DES في وضع CBC مرضية تمامًا ولكن لا يمكنني تشغيلها بعد.فيما يلي مزيد من التفاصيل حول الكود الأصلي:مفتاح الحرف غير الموقع1[10]= {0};unsigned char key2[50]= {0};

int i;
for (i=0;i<8;i++)
    key1[i] = 31+int((i*sqrt((double)i*5)))%100;
key1[9]=0;

for (i=0;i<48;i++)
    key2[i] = 31+int((i*i*sqrt((double)i*2)))%100;
key2[49]=0;
...
// Initialize encrypted buffer
memset(encrypted_buffer, 0, sizeof(encrypted_buffer));

// Add begin Text and End Text to the encrypted message
std::string input;
const char beginText = 2;
const char endText = 3;
input.append(1,beginText);
input.append(bufferToEncrypt);
input.append(1,endText);    

// Add padding
tmp.assign(desPad(input));

des_ncbc_encrypt(reinterpret_cast<const unsigned char *>(tmp.c_str()),     
reinterpret_cast< unsigned char *>(encrypted_buffer), tmp.length(), ks, &initkey, 
DES_ENCRYPT);
...

مما قرأته، يجب أن يكون طول المفتاح 56 (أو 64، ليس واضحًا بالنسبة لي)، لكن هنا يبلغ طوله 48 بايت.

هل كانت مفيدة؟

المحلول

أنا لست خبيرًا في OpenSSL، ولكن أعتقد أن كود C++ يستخدم DES في وضع CBC وبالتالي يحتاج إلى IV (وهذا هو initKey على الأرجح، ولهذا السبب تعتقد أنك بحاجة إلى مفتاحين).إذا كنت على حق، فأنت بحاجة إلى تغيير كود Java الخاص بك لاستخدام DES في وضع CBC أيضًا، وسيتطلب كود Java أيضًا مفتاح تشفير وIV.

نصائح أخرى

ضع في اعتبارك أيضًا أنه لا ينبغي عليك حقًا استخدام فئات sun.misc.* في التعليمات البرمجية الخاصة بك.قد يؤدي هذا إلى تعطيل أجهزة افتراضية أخرى لأنها ليست واجهات برمجة تطبيقات عامة.تحتوي برامج ترميز Apache Commons (من بين برامج أخرى) على تطبيقات Base64 التي لا تتحمل هذه المشكلة.

لست متأكدًا حقًا من سبب استخدام DES الفردي لمفاتيح متعددة.حتى لو كنت تستخدم Triple-DES، أعتقد أنك ستستخدم مفتاحًا واحدًا (مع المزيد من البايتات من البيانات) بدلاً من استخدام مفاتيح منفصلة مع Java Cryptography API.

يجب أن تتطابق الخوارزميات؛إذا كنت تحصل على نتائج مختلفة، فقد يتعلق الأمر بالطريقة التي تتعامل بها مع المفاتيح والنص.ضع في اعتبارك أيضًا أن أحرف Java يبلغ طولها 2 بايت، بينما يبلغ طول أحرف C++ 1 بايت، لذلك قد يكون لذلك علاقة بها.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top