مقدمة

بروتوكول Kerberos 5 يستخدم الآن بنشاط للمصادقة. من ميزات هذا البروتوكول أنه ينفذ المصادقة استنادًا إلى أربعة أعمدة:
- تشفير متماثل.
- التجزئة.
- EDS.
- الطرف الموثوق الثالث.
بدءًا من الإصدار الخامس ، أصبح من الممكن الآن استخدام التشفير غير المتماثل (للتوقيع الإلكتروني). ليس من المنطقي التركيز على تشغيل بروتوكول Kerberos ، لأنه يمكن العثور على وصف الخوارزمية هنا .
لسوء الحظ ، فإن عدد خوارزميات التشفير والتجزئة والتوقيع الرقمي التي يستخدمها هذا البروتوكول ليست كبيرة كما أريد ، لذلك أريد في هذه المقالة إظهار كيفية إضافة سهل وبسيط الخوارزميات الخاصة لتنفيذ هذا البروتوكول من قبل معهد ماساتشوستس للتكنولوجيا . سنضيف خوارزمياتنا المحلية: GOST 28147-89 (ويعرف أيضًا باسم Magma) ، GOST R 34.11-2012 (aka Stribog) و GOST R 34.10-2012 (أود أيضًا أن أكون معروفًا بها ، لكنني لا أعرف :(). جاهز يمكن العثور على حل لهذه الخوارزميات في مستودع التخزين الخاص بي.على جانب العميل ، سوف نستخدم تطبيقات الأجهزة من خوارزميات GOST في Rutoken EDS 2.0 وتطبيقات البرامج الخاصة بهم في مشغل GOST for openssl ، لكن الخيار الأكثر أماناً لتخزين المفاتيح هو عندما يتم إنشاؤها مباشرة على Rutoken لا تترك ذاكرته أثناء عمليات التشفير لهذا الخيار ، رتينجين مطلوب.
قبل البدء في تنفيذ الخوارزميات ، نصف الأماكن الرئيسية التي سيتم فيها إجراء التغييرات. داخل الدليل src / lib / crypto / ، توجد تطبيقات لجميع الخوارزميات المسؤولة عن التشفير المتماثل والتجزئة. لديها 2 تطبيقات لهذه الخوارزميات التشفير: مدمج و openssl. من أجل توفير الوقت والمساحة ، سنضيف ، بالطبع ، تطبيق الخوارزميات باستخدام openssl ، التي كانت موجودة بالفعل (جيدًا ، أو تقريبًا ، ولكن المزيد حول ذلك لاحقًا). لإضافة خوارزميات غير متماثلة ، ستحتاج إلى تعديل البرنامج المساعد src / plugins / preauth / pkinit
إذا لم تكن قد قمت بعد بتكوين Kerberos ، فيمكنك العثور على تعليمات التكوين الأولي والتشغيل هنا . علاوة على ذلك ، يفترض المؤلف أنك تعمل مع مجال AKTIV-TEST.RU
إضافة خوارزميات التجزئة والتشفير المتماثل
كما تم الإعلان عنه سابقًا ، لن نكتب خوارزميات التشفير والتجزئة من البداية ، لكننا سنستخدم تطبيقًا جاهزًا لهذه الخوارزميات في openssl. Openssl مباشرة لا يدعم تنفيذ الخوارزميات المحلية ، لكن لديه قابلية للتنقل في هذه المسألة ويسمح لك بإضافة خوارزميات جديدة باستخدام آلية GOST الخاصة بالمحرك للعمل مع المفاتيح في نظام الملفات وتخزينها على الرمز المميز.
مقدمة صغيرة لمحرك محرك openssl وربط محرك GOST
Engine in openssl هي مكتبة ديناميكية صغيرة تفتح الأحمال في وقت التشغيل حسب الطلب. يجب أن تحتوي كل مكتبة على رموز معينة (وظائف) لتحميل الخوارزميات الضرورية. في هذه الورقة ، سوف نستخدم محرك gost ، الذي يحتوي على جميع خوارزميات التشفير المحلية الضرورية.
التثبيت بسيط للغاية ، على سبيل المثال ، ويستمر كما يلي:
قم بتنزيل تطبيق هذا المحرك من المستودع .
أنشئ مكتبة بها (mkdir build && cd build && cmake ... && make):
mkdir build cd build cmake .. make
في دليل bin (الذي سيظهر في كتالوج الجذر للمشروع !!!) سيكون هناك gost.so مكتبة ديناميكية - هذا هو Engin. سوف تحتاج إلى نقل إلى الدليل حيث يتم تخزين محركات openssl. تعرف على موقع هذا الدليل باستخدام:
openssl version -a | grep ENGINESDIR
الأمر متروك للأخير - تحتاج إلى معرفة openssl أين هو المحرك المحدد وما يسمى. يمكنك القيام بذلك عن طريق تغيير ملف التكوين openssl.cnf. الموقع الذي يمكن العثور عليه باستخدام:
openssl version -a | grep OPENSSLDIR
في نهاية هذا الملف ، ستحتاج إلى إضافة المحتويات التالية:
بعد ذلك ، يجب أن يظهر هذا المحرك في openssl. يمكنك التحقق من أدائها من خلال فرض ، على سبيل المثال ، إنشاء مفتاح خاص في ملف وفقًا لـ GOST R 34.10-2012:
openssl genpkey -engine gost -algorithm gost2012_512 -pkeyopt paramset:A -out client_key.pem
تشير علامة -engine فقط إلى المحرك الذي يجب تحميله قبل بدء العمل حتى تصبح خوارزمية إنشاء المفتاح لـ GOST R 34.10-2012 مرئية.
تطبيق خوارزمية التجزئة
لنبدأ بالأبسط - مع تنفيذ خوارزمية Stribog. لدى Kerberos اتصال قوي بين خوارزميات التجزئة والتشفير ، أي أنه لا يمكنك فقط اختيار واختيار خوارزمية للتشفير ، ولإجراء التجزئة أخرى ، ستحتاج إلى دمج خوارزمية التجزئة والتشفير. سبب هذا غير معروف بالنسبة لي ، ولكن نظرًا لوجود مثل هذه القواعد هناك - دعنا نحاول إنشاء مجموعة من خوارزمية Stribog و AES.
لأن نحن بحاجة إلى الثقة في الاتصال في أماكن مختلفة من برنامجنا ، فلنقم أولاً بإنشاء مكتبة gost_helper صغيرة تحتوي على وظيفة التهيئة للمحرك في openssl ، بالإضافة إلى العديد من الوظائف التي تُرجع سياقات بعض خوارزميات التجزئة للراحة - وهذا سيساعدنا في المستقبل. نقوم بتسمية gost_helper هذه المكتبة وإنشاء ملف رأس ومصدر مناسب لها في الدليل src / lib / crypto / openssl / :
// gost_helper.h #include <openssl/evp.h> // GOST void krb5int_init_gost(); // , const EVP_MD * EVP_gostR3411_2012_256(); const EVP_MD * EVP_gostR3411_2012_512(); // gost_helper.c #include "gost_helper.h" #include <openssl/engine.h> // static ENGINE *eng = NULL; void krb5int_init_gost() { // , if (eng) return; OPENSSL_add_all_algorithms_conf(); ERR_load_crypto_strings(); if (!(eng = ENGINE_by_id("gost"))) { printf("Engine gost doesn't exist"); return; } ENGINE_init(eng); ENGINE_set_default(eng, ENGINE_METHOD_ALL); } const EVP_MD * EVP_gostR3411_2012_256() { krb5int_init_gost(); return EVP_get_digestbynid(NID_id_GostR3411_2012_256); } const EVP_MD * EVP_gostR3411_2012_512() { krb5int_init_gost(); return EVP_get_digestbynid(NID_id_GostR3411_2012_512); }
بعد إضافة المكتبة المساعدة ، ستحتاج إلى الإعلان عن وجودها في Makefile وكتابة تبعيات الملف الخاصة بها. للقيام بذلك ، أضف ما يلي:
تجدر الإشارة إلى أنه في المستقبل ، عند توصيل هذه المكتبة ، سنحتاج إلى إضافة تبعيات بعض الملفات على رأس هذه المكتبة. يتم ذلك ببساطة - تم العثور على الهدف ، حيث تحتاج إلى إضافة التبعية في ملف deps ويتم تسجيل الاعتماد على rel / path / to / gost_helper.h . على سبيل المثال ، في src / lib / crypto / openssl / hash_provider / deps ، ستحتاج إلى إضافة ما يلي:
hash_evp.so hash_evp.po $(OUTPRE)hash_evp.$(OBJEXT): \ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ ... $(srcdir)/../gost_helper.h hash_evp.c
من أجل توفير مساحة في المقالة وتمتد أدمغتك ، لم أعد أهتم بها: كن حذرًا ودقيقًا!
الآن إضافة تطبيقات دالة التجزئة ، كل تطبيقاتها موجودة في src / lib / crypto / openssl / hash_provider / hash_evp.c . هناك سوف تحتاج إلى إضافة ما يلي:
// deps !!! #include "crypto_int.h" #include "gost_helper.h" #include <openssl/evp.h> ... static krb5_error_code hash_sha384(const krb5_crypto_iov *data, size_t num_data, krb5_data *output) { return hash_evp(EVP_sha384(), data, num_data, output); } static krb5_error_code hash_stribog256(const krb5_crypto_iov *data, size_t num_data, krb5_data *output) { return hash_evp(EVP_gostR3411_2012_256(), data, num_data, output); } static krb5_error_code hash_stribog512(const krb5_crypto_iov *data, size_t num_data, krb5_data *output) { return hash_evp(EVP_gostR3411_2012_512(), data, num_data, output); } // /* -- -- -- -- */ const struct krb5_hash_provider krb5int_hash_sha384 = { "SHA-384", 48, 128, hash_sha384 }; const struct krb5_hash_provider krb5int_hash_stribog256 = { "GOSTR34.11-2012-256", 32, 64, hash_stribog256 }; const struct krb5_hash_provider krb5int_hash_stribog512 = { "GOSTR34.11-2012-512", 64, 64, hash_stribog512 };
الآن نحن بحاجة إلى إعلان هذه السياقات في جميع أنحاء المكتبة. للقيام بذلك ، قم بإنشاء وصفها في ملف src / lib / crypto / krb / crypto_int.h .
// , , , krb5_hash_provider - : ... struct krb5_hash_provider { char hash_name[32]; // 8 size_t hashsize, blocksize; krb5_error_code (*hash)(const krb5_crypto_iov *data, size_t num_data, krb5_data *output); }; ... extern const struct krb5_hash_provider krb5int_hash_sha384; extern const struct krb5_hash_provider krb5int_hash_stribog256; extern const struct krb5_hash_provider krb5int_hash_stribog512; ...
سنعلن معرف حزمة Stribog و AES ، ونقدم وحدات الماكرو التي سنتصل بها CKSUMTYPE_STRIBOG_256_AES256 ، CKSUMTYPE_STRIBOG_512_AES256 ، ENCTYPE_AES256_CTS_STRIBOG_256 ، ENCTYP6 يجب التصريح عنها في قالب ملف الرأس src / include / krb5 / krb5.hin . سيبدو شيء مثل هذا:
#define ENCTYPE_ARCFOUR_HMAC_EXP 0x0018 /**< RFC 4757 */ #define ENCTYPE_CAMELLIA128_CTS_CMAC 0x0019 /**< RFC 6803 */ #define ENCTYPE_CAMELLIA256_CTS_CMAC 0x001a /**< RFC 6803 */ #define ENCTYPE_AES256_CTS_STRIBOG_256 0x001b /**< NO RFC */ #define ENCTYPE_AES256_CTS_STRIBOG_512 0x001c /**< NO RFC */ #define ENCTYPE_UNKNOWN 0x01ff ... #define CKSUMTYPE_CMAC_CAMELLIA256 0x0012 /**< RFC 6803 */ #define CKSUMTYPE_MD5_HMAC_ARCFOUR -137 /* Microsoft netlogon */ #define CKSUMTYPE_HMAC_MD5_ARCFOUR -138 /**< RFC 4757 */ #define CKSUMTYPE_STRIBOG_256_AES256 -139 /**< NO RFC */ #define CKSUMTYPE_STRIBOG_512_AES256 -140 /**< NO RFC */
تحتاج الآن إلى إضافة مجموعتين من وظائف التجزئة والتشفير ووظائف التشفير والتجزئة. لماذا اثنين ، إذا كانت معادلة ، تسأل؟ الجواب: أنا لا أعرف ، أم أنها عكاز تاريخي أو وسيلة لتحسين. ومع ذلك ، دعونا نضيف هياكل جديدة إلى الملفات الضرورية:
// src/lib/crypto/krb/cksumtypes.c /* -- -- -- -- -- -- -- " " -- -- -- */ const struct krb5_cksumtypes krb5int_cksumtypes_list[] = { ... { CKSUMTYPE_STRIBOG_256_AES256, "stribog-256-aes256", { 0 }, "STRIBOG256 AES256 key", &krb5int_enc_aes256, &krb5int_hash_stribog256, krb5int_etm_checksum, NULL, 64, 32, 0 }, { CKSUMTYPE_STRIBOG_512_AES256, "stribog-512-aes256", { 0 }, "STRIBOG512 AES256 key", &krb5int_enc_aes256, &krb5int_hash_stribog512, krb5int_etm_checksum, NULL, 64, 64, 0 }, }; // src/lib/crypto/krb/etypes.c : /* -- -- -- -- -- -- -- -- , -- , -- , -- -- -- -- */ const struct krb5_keytypes krb5int_enctypes_list[] = { ... { ENCTYPE_AES256_CTS_STRIBOG_256, "aes256-cts-stribog-256", { "aes256-stribog256" }, "AES-256 CTS mode with 256-bit stribog", &krb5int_enc_aes256, &krb5int_hash_stribog256, 16, krb5int_aes2_crypto_length, krb5int_etm_encrypt, krb5int_etm_decrypt, krb5int_aes2_string_to_key, k5_rand2key_direct, krb5int_aes2_prf, CKSUMTYPE_STRIBOG_256_AES256, 0 /*flags*/, 256 }, { ENCTYPE_AES256_CTS_STRIBOG_512, "aes256-cts-stribog-512", { "aes256-stribog512" }, "AES-256 CTS mode with 512-bit stribog", &krb5int_enc_aes256, &krb5int_hash_stribog512, 16, krb5int_aes2_crypto_length, krb5int_etm_encrypt, krb5int_etm_decrypt, krb5int_aes2_string_to_key, k5_rand2key_direct, krb5int_aes2_prf, CKSUMTYPE_STRIBOG_512_AES256, 0 /*flags*/, 256 }, };
يبدو أن كل شيء ، ولكن لا! ثم هناك مشاكل لن تكون مرئية فقط أثناء عملية تصحيح الأخطاء ، فبعضها كان من الممكن تجنبه عن طريق الإشارة ، على سبيل المثال ، إلى مؤشرات دالة أخرى في الهياكل أعلاه ، لكننا سنذهب بطريقة أكثر تعقيدًا لإظهار ما قد يلزم إصلاحه على طول الطريق. لقد تعلمت كل هذه المشكلات فقط باستخدام مصحح الأخطاء:
// src/lib/crypto/openssl/hmac.c map_digest -- - . . : #include "crypto_int.h" #include "gost_helper.h" #include <openssl/hmac.h> #include <openssl/evp.h> static const EVP_MD * map_digest(const struct krb5_hash_provider *hash) { if (!strncmp(hash->hash_name, "SHA1",4)) return EVP_sha1(); ... else if (!strncmp(hash->hash_name, "GOSTR34.11-2012-256", 19)) return EVP_gostR3411_2012_256(); else if (!strncmp(hash->hash_name, "GOSTR34.11-2012-512", 19)) return EVP_gostR3411_2012_512(); else return NULL; } // src/lib/crypto/openssl/pbkdf2.c krb5int_pbkdf2_hmac, : krb5_error_code krb5int_pbkdf2_hmac(const struct krb5_hash_provider *hash, const krb5_data *out, unsigned long count, const krb5_data *pass, const krb5_data *salt) { const EVP_MD *md = NULL; /* Get the message digest handle corresponding to the hash. */ if (hash == &krb5int_hash_sha1) md = EVP_sha1(); ... else if (hash == &krb5int_hash_stribog256) md = EVP_gostR3411_2012_256(); else if (hash == &krb5int_hash_stribog512) md = EVP_gostR3411_2012_512(); ... return 0; } // src/lib/krb5/krb/init_ctx.c , : static krb5_enctype default_enctype_list[] = { ... ENCTYPE_AES256_CTS_STRIBOG_256, ENCTYPE_AES256_CTS_STRIBOG_512, 0 };
بعد كل هذه التغييرات ، يمكنك التحقق من تشغيل الخوارزمية. سنجمع كل ما قمنا به.
autoconf ./configure --with-crypto-impl=openssl
الآن دعونا نبدأ التحقق. للقيام بذلك ، فلنضع الاستخدام القسري للخوارزميات التي طبقناها في ملفات تكوين Kerberos. قم بما يلي:
وقف krb5kdc:
service krb5-kdc stop
سنصلح ملف تهيئة kdc.conf (لدي /usr/local/var/krb5kdc/kdc.conf بالنسبة لي). تعيين التجزئة القسري باستخدام الخوارزمية المقدمة حديثًا:
[realms] AKTIV-TEST.RU = { master_key_type = aes256-stribog512 supported_enctypes = aes256-stribog512:normal default_tgs_enctypes = aes256-stribog512 default_tkt_enctypes = aes256-stribog512 permitted_enctypes = aes256-stribog512 }
تغييرات مماثلة في ملف التكوين لبروتوكول krb5.conf بأكمله (لدي في /etc/krb5.conf):
[libdefaults] supported_enctypes = aes256-stribog512:normal default_tgs_enctypes = aes256-stribog512 default_tkt_enctypes = aes256-stribog512 permitted_enctypes = aes256-stribog512 # 256
بعد ذلك ، قم بتشغيل krb5kdc منذ إذا تغيرت master_key ، فقد تضطر إلى إنشاء قاعدة البيانات الرئيسية مرة أخرى باستخدام krb5_newrealm.
بعد ذلك ، نقوم بإنشاء جميع المبادئ اللازمة ويمكنك البدء في العمل. حاول المصادقة مع kinit.
سوف نتحقق من أن التجزئة قد حدث وفقًا للخوارزمية المحددة.
باستخدام klist -e.
إذا لم تبدأ الخدمة ، فيمكن البدء من تحت الجذر باستخدام src / kdc / krb5kdc . إذا بدأ كل شيء ، سارت الأمور بسلاسة - مبروك! بخلاف ذلك - للأسف ، لا أقدم علاجًا لجميع المشكلات ، لكني أقدم فقط تعليمة "صغيرة" تحتوي على الخطوات الأساسية التي سيتعين عليك اتخاذها من أجل تنفيذ الخوارزمية الجديدة في Kerberos. وإذا لم ينجح أي شيء من أجلك ، فاختر gdb وانظر إلى أين يحدث الخطأ. يمكنني فقط أن أعطيك بعض النصائح:
- يمكنك إنشاء مشروع في وضع التصحيح إذا قمت بتمريره إلى ./configure CFLAGS = "-g -O0"؛
- يمكن إطلاق krb5kdc في الخلفية باستخدام العلم -n ؛
- آمل ألا يأتي إلى هذا (على الرغم من أنني ما زلت أتوصل إلى تنفيذ خوارزميات غير متماثلة) - قد تحتاج إلى رموز تصحيح opensl - إما تثبيتها من المستودع أو تثبيت openssl من المصدر مع رموز تصحيح الأخطاء ؛
- الشيء نفسه ينطبق على محرك غوست.
يجب أن تكون فكرة هذه المجموعة من النصائح كافية لكي تنقذ نفسك من إضاعة الوقت في البحث عن "المجهول".
تنفيذ خوارزمية التشفير
في هذا القسم ، سأوضح كيف يمكنك إضافة خوارزمية تشفير البيانات الخاصة بك في Kerberos ، وسنحاول إنشاء مجموعة من Magma و Stribog ، المضافة في القسم الأخير. هنا أفترض بالفعل أن مكتبة gost_helper الصغيرة تمت إضافتها بالفعل في القسم الأخير. حسنًا ، مدّ أصابعك وتابع:
أولاً ، نصف الخوارزمية في مكتبتنا libk5crypto من خلال وصفها في ملف الرأس src / lib / crypto / krb / crypto_int.h .
... extern const struct krb5_enc_provider krb5int_enc_camellia256; extern const struct krb5_enc_provider krb5int_enc_gost89; ...
في دليل src / lib / crypto / openssl / enc_provider ، أضف gost.c الكود المصدري ، والذي يحتوي على تطبيق جميع الخوارزميات الضرورية (أخذت الكود المصدري لخوارزمية des كقاعدة). من المهم أن نلاحظ أننا نطبق فقط وضع تشفير cbc ، لذلك للاختبار الذاتي يمكنك أن تأخذ أي وضع تشفير آخر وإضافته:
#include "crypto_int.h" #include "gost_helper.h" #include <openssl/evp.h> #define BLOCK_SIZE 8 static krb5_error_code krb5int_gost_encrypt(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data, size_t num_data) { int ret, olen = BLOCK_SIZE; unsigned char iblock[BLOCK_SIZE], oblock[BLOCK_SIZE]; struct iov_cursor cursor; EVP_CIPHER_CTX *ctx; // , krb5int_gost_encrypt, : krb5int_init_gost(); ctx = EVP_CIPHER_CTX_new(); if (ctx == NULL) return ENOMEM; ret = EVP_EncryptInit_ex(ctx, EVP_get_cipherbynid(NID_gost89_cbc), NULL, key->keyblock.contents, (ivec) ? (unsigned char*)ivec->data : NULL); if (!ret) { EVP_CIPHER_CTX_free(ctx); return KRB5_CRYPTO_INTERNAL; } EVP_CIPHER_CTX_set_padding(ctx,0); k5_iov_cursor_init(&cursor, data, num_data, BLOCK_SIZE, FALSE); while (k5_iov_cursor_get(&cursor, iblock)) { ret = EVP_EncryptUpdate(ctx, oblock, &olen, iblock, BLOCK_SIZE); if (!ret) break; k5_iov_cursor_put(&cursor, oblock); } if (ivec != NULL) memcpy(ivec->data, oblock, BLOCK_SIZE); EVP_CIPHER_CTX_free(ctx); zap(iblock, sizeof(iblock)); zap(oblock, sizeof(oblock)); if (ret != 1) return KRB5_CRYPTO_INTERNAL; return 0; } static krb5_error_code krb5int_gost_decrypt(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data, size_t num_data) { int ret, olen = BLOCK_SIZE; unsigned char iblock[BLOCK_SIZE], oblock[BLOCK_SIZE]; struct iov_cursor cursor; EVP_CIPHER_CTX *ctx; krb5int_init_gost(); ctx = EVP_CIPHER_CTX_new(); if (ctx == NULL) return ENOMEM; ret = EVP_DecryptInit_ex(ctx, EVP_get_cipherbynid(NID_gost89_cbc), NULL, key->keyblock.contents, (ivec) ? (unsigned char*)ivec->data : NULL); if (!ret) { EVP_CIPHER_CTX_free(ctx); return KRB5_CRYPTO_INTERNAL; } EVP_CIPHER_CTX_set_padding(ctx,0); k5_iov_cursor_init(&cursor, data, num_data, BLOCK_SIZE, FALSE); while (k5_iov_cursor_get(&cursor, iblock)) { ret = EVP_DecryptUpdate(ctx, oblock, &olen, (unsigned char *)iblock, BLOCK_SIZE); if (!ret) break; k5_iov_cursor_put(&cursor, oblock); } if (ivec != NULL) memcpy(ivec->data, iblock, BLOCK_SIZE); EVP_CIPHER_CTX_free(ctx); zap(iblock, sizeof(iblock)); zap(oblock, sizeof(oblock)); if (ret != 1) return KRB5_CRYPTO_INTERNAL; return 0; } static krb5_error_code krb5int_gost_init_state (const krb5_keyblock *key, krb5_keyusage usage, krb5_data *state) { state->length = 8; state->data = (void *) malloc(8); if (state->data == NULL) return ENOMEM; memset(state->data, 0, state->length); return 0; } static void krb5int_gost_free_state(krb5_data *state) { free(state->data); *state = empty_data(); } /* -- , -- - -- -- -- -- cbc-mac checksum, , .. -- -- */ const struct krb5_enc_provider krb5int_enc_gost89 = { BLOCK_SIZE, 32, 32, krb5int_gost_encrypt, krb5int_gost_decrypt, NULL, krb5int_gost_init_state, krb5int_gost_free_state };
في قالب src / lib / crypto / openssl / enc_provider / Makefile.in ، نشير إلى ظهور مصدر جديد:
STLIBOBJS= \ des.o \ ... gost.o OBJS= \ $(OUTPRE)des.$(OBJEXT) \ ... $(OUTPRE)gost$(OBJEXT) SRCS= \ $(srcdir)/des.c \ ... $(srcdir)/gost.c
لا تنس تحديد التبعيات في src / lib / crypto / openssl / enc_provider / deps :
gost.so gost.po $(OUTPRE)gost.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../../krb/crypto_int.h \ $(srcdir)/../crypto_mod.h $(top_srcdir)/include/k5-buf.h \ $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-gmt_mktime.h \ $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \ $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \ $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \ $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \ $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \ $(top_srcdir)/include/socket-utils.h $(srcdir)/../gost_helper.h gost.c
أضف معرفات الحزمة إلى src / include / krb5 / krb5.hin :
... #define ENCTYPE_AES256_CTS_STRIBOG_256 0x001b /**< NO RFC */ #define ENCTYPE_AES256_CTS_STRIBOG_512 0x001c /**< NO RFC */ #define ENCTYPE_GOST89_CBC_STRIBOG_256 0x001d /**< SOME GOST */ #define ENCTYPE_GOST89_CBC_STRIBOG_512 0x001e /**< SOME GOST */ #define ENCTYPE_UNKNOWN 0x01ff ... #define CKSUMTYPE_STRIBOG_256_AES256 -139 /**< NO RFC */ #define CKSUMTYPE_STRIBOG_512_AES256 -140 /**< NO RFC */ #define CKSUMTYPE_STRIBOG_256_GOST89 -141 /**< SOME GOST */ #define CKSUMTYPE_STRIBOG_512_GOST89 -142 /**< SOME GOST */
دعنا نصف بنية حزم دالة التجزئة والتشفير ، كما في القسم الأخير:
// src/lib/crypto/krb/cksumtypes.c const struct krb5_cksumtypes krb5int_cksumtypes_list[] = { ... { CKSUMTYPE_STRIBOG_256_GOST89, "stribog-256-gost89", { 0 }, "STRIBOG256 GOST89 key", &krb5int_enc_gost89, &krb5int_hash_stribog256, krb5int_dk_checksum, NULL, 64, 32, 0 }, { CKSUMTYPE_STRIBOG_512_GOST89, "stribog-512-gost89", { 0 }, "STRIBOG512 GOST89 key", &krb5int_enc_gost89, &krb5int_hash_stribog512, krb5int_dk_checksum, NULL, 64, 64, 0 }, }; // src/lib/crypto/krb/etypes.c // , , , aes const struct krb5_keytypes krb5int_enctypes_list[] = { ... { ENCTYPE_GOST89_CBC_STRIBOG_256, "gost89-cbc-stribog-256", { "gost89-stribog256" }, "GOST 28147-89 CBC mode with 256-bit stribog", &krb5int_enc_gost89, &krb5int_hash_stribog256, 16, krb5int_dk_crypto_length, krb5int_dk_encrypt, krb5int_dk_decrypt, krb5int_dk_string_to_key, k5_rand2key_direct, krb5int_dk_prf, CKSUMTYPE_STRIBOG_256_GOST89, 0 /*flags*/, 256 }, { ENCTYPE_GOST89_CBC_STRIBOG_512, "gost89-cbc-stribog-512", { "gost89-stribog512" }, "GOST 28147-89 CBC mode with 512-bit stribog", &krb5int_enc_gost89, &krb5int_hash_stribog512, 16, krb5int_dk_crypto_length, krb5int_dk_encrypt, krb5int_dk_decrypt, krb5int_dk_string_to_key, k5_rand2key_direct, krb5int_dk_prf, CKSUMTYPE_STRIBOG_512_GOST89, 0 /*flags*/, 256 }, };
أضف إلى قائمة أوضاع التشفير الافتراضية في ملف src / lib / krb5 / krb / init_ctx.c :
static krb5_enctype default_enctype_list[] = { ... ENCTYPE_AES256_CTS_STRIBOG_256, ENCTYPE_AES256_CTS_STRIBOG_512, ENCTYPE_GOST89_CBC_STRIBOG_256, ENCTYPE_GOST89_CBC_STRIBOG_512, 0 };
بعد هذه التلاعب ، يمكنك محاولة اختبار الخوارزمية المقدمة حديثًا. يتم الاختبار بالطريقة نفسها كما في القسم الأخير . يمكن اعتبار اسم الحزمة كاسم مستعار (على سبيل المثال ، gost89-stribog512) أو باستخدام اسم الخوارزمية نفسها (على سبيل المثال ، gost89-cbc-stribog-512). آمل أن يعمل كل شيء ، وإلا لا تنسوا ما قلته سابقًا .
إضافة خوارزمية التوقيع الرقمي
الصيحة! ننتقل إلى القسم الأخير من هذه المقالة ونحاول إضافة خوارزمية التوقيع الإلكتروني الخاصة بنا. لا تخف ، مضيفًا أنه أسهل من أي شيء آخر ، لذلك دعونا نبدأ في أقرب وقت ممكن ... رغم أنك لا ، انتظر قليلاً لتبدأ.
التشفير غير المتماثل هو شيء ثقيل الوزن. – : , - . ...
, . , , . . . . , . , . , , — . .
شيء من هذا القبيل. , , . : . , , , , , .
openssl ( )
, -, openssl rtengine. GOST, , .
SDK rutoken sdk/openssl/rtengine/bin/ engine.
librtpkcs11ecp.so.
master OpenSC 8cf1e6f
, openssl.cnf:
engine .
, KDC
kerberos . , .
, , , KDC:
openssl genpkey -engine gost -algorithm gost2012_256 -pkeyopt paramset:B -out CA_key.pem
kdc, , :
[kdcdefaults] ... pkinit_identity = FILE:/var/lib/krb5kdc/KDC.pem,/var/lib/krb5kdc/KDC_key.pem pkinit_anchors = FILE:/var/lib/krb5kdc/CA_cert.pem
[libdefaults]
spake_preauth_groups = edwards25519
3. : ```bash sudo kadmin.local kadmin.local$: modprinc +requires_preauth user
. , , : :
, KDC:
openssl genpkey -engine gost -algorithm gost2012_256 -pkeyopt paramset:B -out client_key.pem
:
pkcs11-tool --module /path/to/module/librtpkcs11ecp.so --keypairgen --key-type GOSTR3410-2012-256:B -l --id 45
:
REALM=AKTIV-TEST.RU; export REALM
: , – :
sudo cp ./client_key.pem client.pem /etc/krb5
( /etc/krb5.conf):
[libdefaults] ... pkinit_anchors = FILE:/var/lib/krb5kdc/CA_cert.pem
, . ! .
, – - 2 ! src/plugins/preauth/pkinit/pkcs11.h src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
pkcs11.h . – , , . ( ). sdk/pkcs11/include/rtpkcs11t.h . :
... #define CKK_TWOFISH (0x21) #define CKK_GOSTR3410 (0x30) #define CKK_GOSTR3411 (0x31) #define CKK_GOST28147 (0x32) #define CKK_VENDOR_DEFINED (1UL << 31) // A mask for new GOST algorithms. // For details visit https://tc26.ru/standarts/perevody/guidelines-the-pkcs-11-extensions-for-implementing-the-gost-r-34-10-2012-and-gost-r-34-11-2012-russian-standards-.html #define NSSCK_VENDOR_PKCS11_RU_TEAM (CKK_VENDOR_DEFINED | 0x54321000) #define CK_VENDOR_PKCS11_RU_TEAM_TK26 NSSCK_VENDOR_PKCS11_RU_TEAM #define CKK_GOSTR3410_512 (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x003) ... #define CKM_AES_MAC_GENERAL (0x1084) #define CKM_AES_CBC_PAD (0x1085) #define CKM_GOSTR3410_KEY_PAIR_GEN (0x1200UL) #define CKM_GOSTR3410 (0x1201UL) #define CKM_GOSTR3410_WITH_GOSTR3411 (0x1202UL) #define CKM_GOSTR3410_KEY_WRAP (0x1203UL) #define CKM_GOSTR3410_DERIVE (0x1204UL) #define CKM_GOSTR3410_512_KEY_PAIR_GEN (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x005) #define CKM_GOSTR3410_512 (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x006) #define CKM_GOSTR3410_12_DERIVE (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x007) #define CKM_GOSTR3410_WITH_GOSTR3411_12_256 (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x008) #define CKM_GOSTR3410_WITH_GOSTR3411_12_512 (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x009) #define CKM_GOSTR3411 (0x1210UL) #define CKM_GOSTR3411_HMAC (0x1211UL) #define CKM_GOSTR3411_12_256 (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x012) #define CKM_GOSTR3411_12_512 (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x013) #define CKM_GOSTR3411_12_256_HMAC (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x014) #define CKM_GOSTR3411_12_512_HMAC (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x015) #define CKM_GOST28147_KEY_GEN (0x1220UL) #define CKM_GOST28147_ECB (0x1221UL) #define CKM_GOST28147 (0x1222UL) #define CKM_GOST28147_MAC (0x1223UL) #define CKM_GOST28147_KEY_WRAP (0x1224UL)
, .
pkinit_crypto_openssl.c , , . get_key, .. - :
#include <dirent.h> #include <arpa/inet.h> #include <openssl/engine.h> static ENGINE *eng = NULL; krb5int_init_engines() { if (eng) return; OPENSSL_add_all_algorithms_conf(); ERR_load_crypto_strings(); if (!(eng = ENGINE_by_id("rtengine"))) { printf("Engine rtengine doesn't exist"); return; } ENGINE_init(eng); ENGINE_set_default(eng, ENGINE_METHOD_ALL); if (!(eng = ENGINE_by_id("gost"))) { printf("Engine gost doesn't exist"); return; } ENGINE_init(eng); ENGINE_set_default(eng, ENGINE_METHOD_ALL); } ... get_key(krb5_context context, pkinit_identity_crypto_context id_cryptoctx, char *filename, const char *fsname, EVP_PKEY **retkey, const char *password) { ... krb5_error_code retval; krb5int_init_engines(); ... } ... int pkinit_openssl_init() { /* Initialize OpenSSL. */ ERR_load_crypto_strings(); OpenSSL_add_all_algorithms(); krb5int_init_engines(); return 0; }
. – RSA , sha1. , . , , . , .. RSA :
// krb5_error_code pkinit_find_private_key(pkinit_identity_crypto_context id_cryptoctx, CK_ATTRIBUTE_TYPE usage, CK_OBJECT_HANDLE *objp) { ... true_false = TRUE; attrs[nattrs].type = usage; attrs[nattrs].pValue = &true_false; attrs[nattrs].ulValueLen = sizeof true_false; nattrs++; #endif // keytype = CKK_RSA; // attrs[nattrs].type = CKA_KEY_TYPE; // attrs[nattrs].pValue = &keytype; // attrs[nattrs].ulValueLen = sizeof keytype; // nattrs++; ... } // : static int ckk_key_to_nid(CK_KEY_TYPE type) { switch(type){ case CKK_GOSTR3410: return NID_id_GostR3410_2012_256; case CKK_GOSTR3410_512: return NID_id_GostR3410_2012_512; default: return NID_rsa; } } // , , : static int pkinit_get_pkey_type(krb5_context context, pkinit_identity_crypto_context id_cryptoctx) { CK_OBJECT_HANDLE obj; CK_ATTRIBUTE attrs[1]; CK_KEY_TYPE key_type; int r; // : if (pkinit_open_session(context, id_cryptoctx)) { pkiDebug("can't open pkcs11 session\n"); return NID_rsa; } // : if (pkinit_find_private_key(id_cryptoctx, CKA_SIGN, &obj)) { return NID_rsa; } // : attrs[0].type = CKA_KEY_TYPE; attrs[0].pValue = &key_type; attrs[0].ulValueLen = sizeof (key_type); if ((r = id_cryptoctx->p11->C_GetAttributeValue(id_cryptoctx->session, obj, attrs, 1)) != CKR_OK) { pkiDebug("C_GetAttributeValue: %s\n Used RSA\n", pkinit_pkcs11_code_to_text(r)); return NID_rsa; } // : return ckk_key_to_nid(key_type); } // , , : static int pkey_to_digest_nid(const EVP_PKEY* const pkey) { switch (EVP_PKEY_id(pkey)) { case NID_id_GostR3410_2012_256: return NID_id_GostR3411_2012_256; case NID_id_GostR3410_2012_512: return NID_id_GostR3411_2012_512; case NID_id_GostR3410_2001: return NID_id_GostR3411_2012_256; default: return NID_sha1; } } // , : static int get_digest_nid(krb5_context context, const pkinit_identity_crypto_context id_cryptctx) { int nid; // ( ), NID , if (id_cryptctx->my_key) { nid = EVP_PKEY_id(id_cryptctx->my_key); } else { nid = pkinit_get_pkey_type(context, id_cryptctx); } switch (nid) { case NID_id_GostR3410_2012_256: return NID_id_GostR3411_2012_256; case NID_id_GostR3410_2012_512: return NID_id_GostR3411_2012_512; case NID_id_GostR3410_2001: return NID_id_GostR3411_2012_256; default: return NID_sha1; } } // , : static int get_alg_nid(krb5_context context, const pkinit_identity_crypto_context id_cryptctx) { int nid; if (id_cryptctx->my_key) { nid = EVP_PKEY_id(id_cryptctx->my_key); } else { nid = pkinit_get_pkey_type(context, id_cryptctx); } switch (nid) { case NID_id_GostR3410_2012_256: return NID_id_tc26_signwithdigest_gost3410_2012_256; case NID_id_GostR3410_2012_512: return NID_id_tc26_signwithdigest_gost3410_2012_512; case NID_id_GostR3410_2001: return NID_id_tc26_signwithdigest_gost3410_2012_256; default: return NID_sha1WithRSAEncryption; } } // : static CK_MECHANISM_TYPE get_mech_type(krb5_context context, const pkinit_identity_crypto_context id_cryptctx) { int nid; if (id_cryptctx->my_key) { nid = EVP_PKEY_id(id_cryptctx->my_key); } else { nid = pkinit_get_pkey_type(context, id_cryptctx); } switch (nid) { case NID_id_GostR3410_2012_256: return CKM_GOSTR3410_WITH_GOSTR3411_12_256; case NID_id_GostR3410_2012_512: return CKM_GOSTR3410_WITH_GOSTR3411_12_512; case NID_id_GostR3410_2001: return CKM_GOSTR3410_WITH_GOSTR3411_12_256; default: return CKM_RSA_PKCS; } }
cms_signeddata_create create_signature :
krb5_error_code cms_signeddata_create(krb5_context context, pkinit_plg_crypto_context plg_cryptoctx, pkinit_req_crypto_context req_cryptoctx, pkinit_identity_crypto_context id_cryptoctx, int cms_msg_type, int include_certchain, unsigned char *data, unsigned int data_len, unsigned char **signed_data, unsigned int *signed_data_len) { ... /* Set digest algs */ p7si->digest_alg->algorithm = OBJ_nid2obj( get_digest_nid(context, id_cryptoctx)); ... p7si->digest_enc_alg->algorithm = OBJ_nid2obj(get_alg_nid(context, id_cryptoctx)); ... EVP_DigestInit_ex(ctx, EVP_get_digestbynid(get_digest_nid(context, id_cryptoctx)), NULL); ... alen = (unsigned int )ASN1_item_i2d((ASN1_VALUE *) sk, &abuf, ASN1_ITEM_rptr(PKCS7_ATTR_SIGN)); ... // , ( ): if (id_cryptoctx->pkcs11_method == 1 && get_digest_nid(context, id_cryptoctx) == NID_sha1) { } static krb5_error_code create_signature(unsigned char **sig, unsigned int *sig_len, unsigned char *data, unsigned int data_len, EVP_PKEY *pkey) { ... EVP_SignInit(ctx, EVP_get_digestbynid(pkey_to_digest_nid(pkey))); ... } // : static krb5_error_code pkinit_sign_data_pkcs11(krb5_context context, pkinit_identity_crypto_context id_cryptoctx, unsigned char *data, unsigned int data_len, unsigned char **sig, unsigned int *sig_len) { ... mech.mechanism = get_mech_type(context, id_cryptoctx); mech.pParameter = NULL; mech.ulParameterLen = 0; ... }
, ( , , ):
sudo kinit user
user, , .
, .