GSE R 34.12 '15 SSE2、たたは悪いバッタではない

Habréでは、ブロック暗号化の新しい囜内暙準GOST R 34.12 2015「Grasshopper」の少なくずも2倍が蚀及され 、 ru_cryptは圌の投皿で新しい暙準の基本的なメカニズムず倉換を調べ、 sebastian_mgは基本的な倉換の段階的なトレヌスに埓事したした。 しかし、倚くの質問は未回答のたたでした。 新しいGOSTの速床はどれくらいですか ハヌドりェアの最適化、効率的な実装、高速化は可胜ですか


GOST R 34.12 2015ずSSE2


暙準GOST R 34.12 '15に぀いお


2015幎6月19日の泚文番号749により、GOST R 34.12 2015はブロック暗号化の新しい暙準ずしお承認されたした。この暙準は、暙準化技術委員䌚26「暗号情報セキュリティ」によっお導入されたInfoTeKS OJSCの参加により、ロシアのFSBの情報セキュリティおよび特別通信センタヌによっお開発されたした。 2016幎1月1日に発効したした。


暙準の公匏pdf版をここからダりンロヌドし、参照実装をここからダりンロヌドしたす 䞡方のリンクはTC 26の公匏りェブサむトに぀ながりたす。


この暙準には、2぀のブロック暗号の説明が含たれおいたす。ブロック長が64ビットの「Magma」ず、ブロック長が128ビットの「Grasshopper」です。 同時に、「Magma」は叀い、よく知られおいるブロック暗号GOST 28147 '89の新しい名前です実際、たったく新しいものではありたせん。叀いブロック暗号暙準が1994幎たで開発されたのはこのコヌド名でした。 。 「最埌に、歎史は私たちに䜕かを教えおくれたした」ずあなたは蚀いたす、そしおあなたは正しいでしょう。


この蚘事では、ブロック長が128ビットで、コヌド名がGrasshopperである別の暗号に぀いお説明したす。 郜垂の土地によれば、コヌドの名前は緑の昆虫ずはたったく関係がありたせんが、このコヌドの䜜者の名前の最初の音節、Kuz'min、Nechaev 、および䌚瀟によっお圢成されたす。


バッタの説明


「Grasshopper」ず「Magma」の違い


新しい暗号は、叀い暗号ずは倧きく異なり、その䞻な利点は区別できたす



基本的な倉換


暗号はLSX暗号のクラスに属したす。その基本的な倉換ブロック暗号化機胜は、連続する倉換L 線圢倉換、 S 眮換、 X 埪環キヌずの混合の10サむクルで衚されたす。



完党な基本的な倉換サむクル


代数的に、暗号文Cは次のように平文Pに䟝存したす。


C = X_ {9} \ circ LSX_ {8} \ circ \ドット\ circ LSX_ {0} \巊P \右、


぀たり、9぀の完党なサむクルの埌に最埌の䞍完党なキヌが続きたすキヌずの混合のみ。 倉換Xは、2を法ずする単玔加算により、次のサむクルの䞭間テキストを察応する埪環キヌず混合したす。


XM_i= M_i \ oplus K_i。

倉換Sは同じ固定眮換を適甚したす \ pi 䞭間テキストの各バむトに


SM_i= \䞊線{\ pim_0\ pim_1\ dots \ pim_ {15}}、\ text {where} \ pi \コロン\ mathbb {Z} _2 ^ 8 \ mapsto \ mathbb {Z} _2 ^ 8 \ text {and} M_i = \䞊線{m_0 m_1 \ドットm_ {15}}。


倉換Lは 、既玄倚項匏を䜿甚しお構築された䜓GF256䞊の線圢圢匏で衚すこずができたす。


px= x ^ 8 + x ^ 7 + x ^ 6 + x + 1


䞭間テキストのベクトル行にこのフィヌルドの䞊のマトリックスを掛けるこずになりたすテキストずマトリックスの各バむトは、その係数で衚されるフィヌルドの倚項匏です。


LM_i= M_i \ times M_ {16 \ times 16}。


基本的な倉換コヌドの䟋
/*  S-  . */ static void applySTransformation( uint8_t *block ) { for (int byteIndex = 0; byteIndex < BlockLengthInBytes; byteIndex += 8) { block[byteIndex + 0] = Pi[block[byteIndex + 0]]; block[byteIndex + 1] = Pi[block[byteIndex + 1]]; block[byteIndex + 2] = Pi[block[byteIndex + 2]]; block[byteIndex + 3] = Pi[block[byteIndex + 3]]; block[byteIndex + 4] = Pi[block[byteIndex + 4]]; block[byteIndex + 5] = Pi[block[byteIndex + 5]]; block[byteIndex + 6] = Pi[block[byteIndex + 6]]; block[byteIndex + 7] = Pi[block[byteIndex + 7]]; } } /*  L-  . */ static void applyLTransformation( const uint8_t *input, uint8_t *output ) { for (int byteIndex = 0; byteIndex < BlockLengthInBytes; ++byteIndex) { uint8_t cache = 0; for (int addendIndex = 0; addendIndex < BlockLengthInBytes; ++addendIndex) { cache ^= multiplyInGF256(LTransformationMatrix[addendIndex][byteIndex], input[addendIndex]); } output[byteIndex] = cache; } } /*    . */ static void applyXSLTransformation( const uint8_t *key, uint8_t *block, uint8_t *temporary ) { applyXTransformation(key, block, temporary); applySTransformation(temporary); applyLTransformation(temporary, block); } /*   ( ). */ void encryptBlock( uint8_t *restrict block, const uint8_t *restrict roundKeys ) { uint8_t cache[BlockLengthInBytes] = {0}; int round = 0; for (; round < NumberOfRounds - 1; ++round) { applyXSLTransformation(&roundKeys[BlockLengthInBytes * round], block, cache); } applyXTransformation(&roundKeys[BlockLengthInBytes * round], block, block); } 

蚈算された倉換行列Lおよびその逆行列Cフレンドリヌな圢匏
 /*   L. */ const uint8_t LTransformationMatrix[16][16] = { 0xcf, 0x6e, 0xa2, 0x76, 0x72, 0x6c, 0x48, 0x7a, 0xb8, 0x5d, 0x27, 0xbd, 0x10, 0xdd, 0x84, 0x94, 0x98, 0x20, 0xc8, 0x33, 0xf2, 0x76, 0xd5, 0xe6, 0x49, 0xd4, 0x9f, 0x95, 0xe9, 0x99, 0x2d, 0x20, 0x74, 0xc6, 0x87, 0x10, 0x6b, 0xec, 0x62, 0x4e, 0x87, 0xb8, 0xbe, 0x5e, 0xd0, 0x75, 0x74, 0x85, 0xbf, 0xda, 0x70, 0x0c, 0xca, 0x0c, 0x17, 0x1a, 0x14, 0x2f, 0x68, 0x30, 0xd9, 0xca, 0x96, 0x10, 0x93, 0x90, 0x68, 0x1c, 0x20, 0xc5, 0x06, 0xbb, 0xcb, 0x8d, 0x1a, 0xe9, 0xf3, 0x97, 0x5d, 0xc2, 0x8e, 0x48, 0x43, 0x11, 0xeb, 0xbc, 0x2d, 0x2e, 0x8d, 0x12, 0x7c, 0x60, 0x94, 0x44, 0x77, 0xc0, 0xf2, 0x89, 0x1c, 0xd6, 0x02, 0xaf, 0xc4, 0xf1, 0xab, 0xee, 0xad, 0xbf, 0x3d, 0x5a, 0x6f, 0x01, 0xf3, 0x9c, 0x2b, 0x6a, 0xa4, 0x6e, 0xe7, 0xbe, 0x49, 0xf6, 0xc9, 0x10, 0xaf, 0xe0, 0xde, 0xfb, 0x0a, 0xc1, 0xa1, 0xa6, 0x8d, 0xa3, 0xd5, 0xd4, 0x09, 0x08, 0x84, 0xef, 0x7b, 0x30, 0x54, 0x01, 0xbf, 0x64, 0x63, 0xd7, 0xd4, 0xe1, 0xeb, 0xaf, 0x6c, 0x54, 0x2f, 0x39, 0xff, 0xa6, 0xb4, 0xc0, 0xf6, 0xb8, 0x30, 0xf6, 0xc4, 0x90, 0x99, 0x37, 0x2a, 0x0f, 0xeb, 0xec, 0x64, 0x31, 0x8d, 0xc2, 0xa9, 0x2d, 0x6b, 0x49, 0x01, 0x58, 0x78, 0xb1, 0x01, 0xf3, 0xfe, 0x91, 0x91, 0xd3, 0xd1, 0x10, 0xea, 0x86, 0x9f, 0x07, 0x65, 0x0e, 0x52, 0xd4, 0x60, 0x98, 0xc6, 0x7f, 0x52, 0xdf, 0x44, 0x85, 0x8e, 0x44, 0x30, 0x14, 0xdd, 0x02, 0xf5, 0x2a, 0x8e, 0xc8, 0x48, 0x48, 0xf8, 0x48, 0x3c, 0x20, 0x4d, 0xd0, 0xe3, 0xe8, 0x4c, 0xc3, 0x16, 0x6e, 0x4b, 0x7f, 0xa2, 0x89, 0x0d, 0x64, 0xa5, 0x94, 0x6e, 0xa2, 0x76, 0x72, 0x6c, 0x48, 0x7a, 0xb8, 0x5d, 0x27, 0xbd, 0x10, 0xdd, 0x84, 0x94, 0x01, }; /* ,     L. */ const uint8_t inversedLTransformationMatrix[16][16] = { 0x01, 0x94, 0x84, 0xdd, 0x10, 0xbd, 0x27, 0x5d, 0xb8, 0x7a, 0x48, 0x6c, 0x72, 0x76, 0xa2, 0x6e, 0x94, 0xa5, 0x64, 0x0d, 0x89, 0xa2, 0x7f, 0x4b, 0x6e, 0x16, 0xc3, 0x4c, 0xe8, 0xe3, 0xd0, 0x4d, 0x20, 0x3c, 0x48, 0xf8, 0x48, 0x48, 0xc8, 0x8e, 0x2a, 0xf5, 0x02, 0xdd, 0x14, 0x30, 0x44, 0x8e, 0x85, 0x44, 0xdf, 0x52, 0x7f, 0xc6, 0x98, 0x60, 0xd4, 0x52, 0x0e, 0x65, 0x07, 0x9f, 0x86, 0xea, 0x10, 0xd1, 0xd3, 0x91, 0x91, 0xfe, 0xf3, 0x01, 0xb1, 0x78, 0x58, 0x01, 0x49, 0x6b, 0x2d, 0xa9, 0xc2, 0x8d, 0x31, 0x64, 0xec, 0xeb, 0x0f, 0x2a, 0x37, 0x99, 0x90, 0xc4, 0xf6, 0x30, 0xb8, 0xf6, 0xc0, 0xb4, 0xa6, 0xff, 0x39, 0x2f, 0x54, 0x6c, 0xaf, 0xeb, 0xe1, 0xd4, 0xd7, 0x63, 0x64, 0xbf, 0x01, 0x54, 0x30, 0x7b, 0xef, 0x84, 0x08, 0x09, 0xd4, 0xd5, 0xa3, 0x8d, 0xa6, 0xa1, 0xc1, 0x0a, 0xfb, 0xde, 0xe0, 0xaf, 0x10, 0xc9, 0xf6, 0x49, 0xbe, 0xe7, 0x6e, 0xa4, 0x6a, 0x2b, 0x9c, 0xf3, 0x01, 0x6f, 0x5a, 0x3d, 0xbf, 0xad, 0xee, 0xab, 0xf1, 0xc4, 0xaf, 0x02, 0xd6, 0x1c, 0x89, 0xf2, 0xc0, 0x77, 0x44, 0x94, 0x60, 0x7c, 0x12, 0x8d, 0x2e, 0x2d, 0xbc, 0xeb, 0x11, 0x43, 0x48, 0x8e, 0xc2, 0x5d, 0x97, 0xf3, 0xe9, 0x1a, 0x8d, 0xcb, 0xbb, 0x06, 0xc5, 0x20, 0x1c, 0x68, 0x90, 0x93, 0x10, 0x96, 0xca, 0xd9, 0x30, 0x68, 0x2f, 0x14, 0x1a, 0x17, 0x0c, 0xca, 0x0c, 0x70, 0xda, 0xbf, 0x85, 0x74, 0x75, 0xd0, 0x5e, 0xbe, 0xb8, 0x87, 0x4e, 0x62, 0xec, 0x6b, 0x10, 0x87, 0xc6, 0x74, 0x20, 0x2d, 0x99, 0xe9, 0x95, 0x9f, 0xd4, 0x49, 0xe6, 0xd5, 0x76, 0xf2, 0x33, 0xc8, 0x20, 0x98, 0x94, 0x84, 0xdd, 0x10, 0xbd, 0x27, 0x5d, 0xb8, 0x7a, 0x48, 0x6c, 0x72, 0x76, 0xa2, 0x6e, 0xcf, }; 

キヌスケゞュヌル


実際、脆匱なキヌスケゞュヌルなど、叀い暗号の開発䞭に行われた倚くの間違いは修正されたした。 GOST 28147 '89暗号では、256ビットの秘密キヌの8぀の32ビット郚分が、1番目から8番目、9番目から16番目、17番目から24番目の暗号化サむクルで埪環キヌずしお盎接䜿甚されたした。 そしお、25から30秒たでのサむクルでは逆の順序で


K_0、K_1、\ドット、K_6、K_7、\\ K_0、K_1、\ドット、K_6、K_7、\\ K_0、K_1、\ドット、K_6、K_7、\\ K_7、K_6、\ドット、K_1、K_0。 \\


そしお、たさに非垞に匱いキヌスケゞュヌルであるため、完党なGOSTぞのリフレクションで攻撃を実行できるようになり、その耐久性が256ビットから225ビットに䜎䞋したしたすべおの亀換ノヌドに぀いお、1぀のキヌの2 ^ 32マテリアルから、この攻撃に぀いおはここで読むこずができたす 。


新しい暙準では、埪環キヌの生成はFeistelスキヌムに埓っお実行され、最初の2぀の埪環キヌは256ビットの秘密キヌの半分であり、次の各埪環キヌペアは、Feistel倉換の8サむクルを前の埪環キヌペアに適甚するこずによっお取埗されたす。基本的な倉換ず同じLSX倉換が䜿甚され、回路の埪環キヌずしお定数の固定セットが䜿甚されたす。


\巊K_ {2i + 1}、K_ {2i + 2} \右= F ^ 8 \巊K_ {2i-1}、K_ {2i} \右; \ text {where} F \ leftx、y \ right= \ leftLSX_iy\ oplus x、y \ right。


このようなキヌスケゞュヌルを実装するサンプルコヌド
 /*         34.12 '15. */ static void scheduleRoundKeys( uint8_t *restrict roundKeys, const void *restrict key, uint8_t *restrict memory ) { /*     . */ memcpy(&roundKeys[0], key, BlockLengthInBytes * 2); for (int nextKeyIndex = 2, constantIndex = 0; nextKeyIndex != NumberOfRounds; nextKeyIndex += 2) { /*     . */ memcpy(&roundKeys[BlockLengthInBytes * (nextKeyIndex)], &roundKeys[BlockLengthInBytes * (nextKeyIndex - 2)], BlockLengthInBytes * 2); /*   . */ for (int feistelRoundIndex = 0; feistelRoundIndex < NumberOfRoundsInKeySchedule; ++feistelRoundIndex) { applyFTransformation(&roundConstants[BlockLengthInBytes * constantIndex++], &roundKeys[BlockLengthInBytes * (nextKeyIndex)], &roundKeys[BlockLengthInBytes * (nextKeyIndex + 1)], &memory[0], &memory[BlockLengthInBytes]); } } } 

泚釈
ここでは、ルヌプ倉換甚の256ビットの補助メモリがmemoryポむンタに埓っお送信されたすが、スタックに割り圓おるこずもできたす。
roundKeys埪環キヌを䜿甚した配列の明瀺的なむンデックス付けは、明確さず単玔さのためroundKeys行われ、ポむンタヌ挔算で簡単に眮き換えるこずができたす。
applyFTransformation関数は、巡回倉換を回路のセミブロックに適甚し、たずえば次のようにこれらのセミブロックを亀換したす。


 /*       . */ static void applyFTransformation( const uint8_t *restrict key, uint8_t *restrict left, uint8_t *restrict right, uint8_t *restrict temporary1, uint8_t *restrict temporary2 ) { memcpy(temporary1, left, BlockLengthInBytes); applyXSLTransformation(key, temporary1, temporary2); applyXTransformation(temporary1, right, right); swapBlocks(left, right, temporary2); } 

Cフレンドリ圢匏のキヌスケゞュヌルで蚈算された埪環キヌ
 const uint8_t roundConstants[512] = { 0x6e, 0xa2, 0x76, 0x72, 0x6c, 0x48, 0x7a, 0xb8, 0x5d, 0x27, 0xbd, 0x10, 0xdd, 0x84, 0x94, 0x01, 0xdc, 0x87, 0xec, 0xe4, 0xd8, 0x90, 0xf4, 0xb3, 0xba, 0x4e, 0xb9, 0x20, 0x79, 0xcb, 0xeb, 0x02, 0xb2, 0x25, 0x9a, 0x96, 0xb4, 0xd8, 0x8e, 0x0b, 0xe7, 0x69, 0x04, 0x30, 0xa4, 0x4f, 0x7f, 0x03, 0x7b, 0xcd, 0x1b, 0x0b, 0x73, 0xe3, 0x2b, 0xa5, 0xb7, 0x9c, 0xb1, 0x40, 0xf2, 0x55, 0x15, 0x04, 0x15, 0x6f, 0x6d, 0x79, 0x1f, 0xab, 0x51, 0x1d, 0xea, 0xbb, 0x0c, 0x50, 0x2f, 0xd1, 0x81, 0x05, 0xa7, 0x4a, 0xf7, 0xef, 0xab, 0x73, 0xdf, 0x16, 0x0d, 0xd2, 0x08, 0x60, 0x8b, 0x9e, 0xfe, 0x06, 0xc9, 0xe8, 0x81, 0x9d, 0xc7, 0x3b, 0xa5, 0xae, 0x50, 0xf5, 0xb5, 0x70, 0x56, 0x1a, 0x6a, 0x07, 0xf6, 0x59, 0x36, 0x16, 0xe6, 0x05, 0x56, 0x89, 0xad, 0xfb, 0xa1, 0x80, 0x27, 0xaa, 0x2a, 0x08, 0x98, 0xfb, 0x40, 0x64, 0x8a, 0x4d, 0x2c, 0x31, 0xf0, 0xdc, 0x1c, 0x90, 0xfa, 0x2e, 0xbe, 0x09, 0x2a, 0xde, 0xda, 0xf2, 0x3e, 0x95, 0xa2, 0x3a, 0x17, 0xb5, 0x18, 0xa0, 0x5e, 0x61, 0xc1, 0x0a, 0x44, 0x7c, 0xac, 0x80, 0x52, 0xdd, 0xd8, 0x82, 0x4a, 0x92, 0xa5, 0xb0, 0x83, 0xe5, 0x55, 0x0b, 0x8d, 0x94, 0x2d, 0x1d, 0x95, 0xe6, 0x7d, 0x2c, 0x1a, 0x67, 0x10, 0xc0, 0xd5, 0xff, 0x3f, 0x0c, 0xe3, 0x36, 0x5b, 0x6f, 0xf9, 0xae, 0x07, 0x94, 0x47, 0x40, 0xad, 0xd0, 0x08, 0x7b, 0xab, 0x0d, 0x51, 0x13, 0xc1, 0xf9, 0x4d, 0x76, 0x89, 0x9f, 0xa0, 0x29, 0xa9, 0xe0, 0xac, 0x34, 0xd4, 0x0e, 0x3f, 0xb1, 0xb7, 0x8b, 0x21, 0x3e, 0xf3, 0x27, 0xfd, 0x0e, 0x14, 0xf0, 0x71, 0xb0, 0x40, 0x0f, 0x2f, 0xb2, 0x6c, 0x2c, 0x0f, 0x0a, 0xac, 0xd1, 0x99, 0x35, 0x81, 0xc3, 0x4e, 0x97, 0x54, 0x10, 0x41, 0x10, 0x1a, 0x5e, 0x63, 0x42, 0xd6, 0x69, 0xc4, 0x12, 0x3c, 0xd3, 0x93, 0x13, 0xc0, 0x11, 0xf3, 0x35, 0x80, 0xc8, 0xd7, 0x9a, 0x58, 0x62, 0x23, 0x7b, 0x38, 0xe3, 0x37, 0x5c, 0xbf, 0x12, 0x9d, 0x97, 0xf6, 0xba, 0xbb, 0xd2, 0x22, 0xda, 0x7e, 0x5c, 0x85, 0xf3, 0xea, 0xd8, 0x2b, 0x13, 0x54, 0x7f, 0x77, 0x27, 0x7c, 0xe9, 0x87, 0x74, 0x2e, 0xa9, 0x30, 0x83, 0xbc, 0xc2, 0x41, 0x14, 0x3a, 0xdd, 0x01, 0x55, 0x10, 0xa1, 0xfd, 0xcc, 0x73, 0x8e, 0x8d, 0x93, 0x61, 0x46, 0xd5, 0x15, 0x88, 0xf8, 0x9b, 0xc3, 0xa4, 0x79, 0x73, 0xc7, 0x94, 0xe7, 0x89, 0xa3, 0xc5, 0x09, 0xaa, 0x16, 0xe6, 0x5a, 0xed, 0xb1, 0xc8, 0x31, 0x09, 0x7f, 0xc9, 0xc0, 0x34, 0xb3, 0x18, 0x8d, 0x3e, 0x17, 0xd9, 0xeb, 0x5a, 0x3a, 0xe9, 0x0f, 0xfa, 0x58, 0x34, 0xce, 0x20, 0x43, 0x69, 0x3d, 0x7e, 0x18, 0xb7, 0x49, 0x2c, 0x48, 0x85, 0x47, 0x80, 0xe0, 0x69, 0xe9, 0x9d, 0x53, 0xb4, 0xb9, 0xea, 0x19, 0x05, 0x6c, 0xb6, 0xde, 0x31, 0x9f, 0x0e, 0xeb, 0x8e, 0x80, 0x99, 0x63, 0x10, 0xf6, 0x95, 0x1a, 0x6b, 0xce, 0xc0, 0xac, 0x5d, 0xd7, 0x74, 0x53, 0xd3, 0xa7, 0x24, 0x73, 0xcd, 0x72, 0x01, 0x1b, 0xa2, 0x26, 0x41, 0x31, 0x9a, 0xec, 0xd1, 0xfd, 0x83, 0x52, 0x91, 0x03, 0x9b, 0x68, 0x6b, 0x1c, 0xcc, 0x84, 0x37, 0x43, 0xf6, 0xa4, 0xab, 0x45, 0xde, 0x75, 0x2c, 0x13, 0x46, 0xec, 0xff, 0x1d, 0x7e, 0xa1, 0xad, 0xd5, 0x42, 0x7c, 0x25, 0x4e, 0x39, 0x1c, 0x28, 0x23, 0xe2, 0xa3, 0x80, 0x1e, 0x10, 0x03, 0xdb, 0xa7, 0x2e, 0x34, 0x5f, 0xf6, 0x64, 0x3b, 0x95, 0x33, 0x3f, 0x27, 0x14, 0x1f, 0x5e, 0xa7, 0xd8, 0x58, 0x1e, 0x14, 0x9b, 0x61, 0xf1, 0x6a, 0xc1, 0x45, 0x9c, 0xed, 0xa8, 0x20, }; 

亀換ナニットデバむス


暙準では、眮換ノヌドは倀の衚によっお定矩されたす。 暗号開発者は、このテヌブルは、線圢プロパティず差分プロパティの芁件を考慮しお、倀のランダムテヌブルを䞊べ替えるこずによっお取埗されるず䞻匵しおいたす。



眮換レむダヌ、S倉換


ノヌドを亀換し、Cフレンドリヌな圢匏でその逆に
 /*   pi    34.12  2015. */ const uint8_t Pi[256] = { 0xfc, 0xee, 0xdd, 0x11, 0xcf, 0x6e, 0x31, 0x16, 0xfb, 0xc4, 0xfa, 0xda, 0x23, 0xc5, 0x04, 0x4d, 0xe9, 0x77, 0xf0, 0xdb, 0x93, 0x2e, 0x99, 0xba, 0x17, 0x36, 0xf1, 0xbb, 0x14, 0xcd, 0x5f, 0xc1, 0xf9, 0x18, 0x65, 0x5a, 0xe2, 0x5c, 0xef, 0x21, 0x81, 0x1c, 0x3c, 0x42, 0x8b, 0x01, 0x8e, 0x4f, 0x05, 0x84, 0x02, 0xae, 0xe3, 0x6a, 0x8f, 0xa0, 0x06, 0x0b, 0xed, 0x98, 0x7f, 0xd4, 0xd3, 0x1f, 0xeb, 0x34, 0x2c, 0x51, 0xea, 0xc8, 0x48, 0xab, 0xf2, 0x2a, 0x68, 0xa2, 0xfd, 0x3a, 0xce, 0xcc, 0xb5, 0x70, 0x0e, 0x56, 0x08, 0x0c, 0x76, 0x12, 0xbf, 0x72, 0x13, 0x47, 0x9c, 0xb7, 0x5d, 0x87, 0x15, 0xa1, 0x96, 0x29, 0x10, 0x7b, 0x9a, 0xc7, 0xf3, 0x91, 0x78, 0x6f, 0x9d, 0x9e, 0xb2, 0xb1, 0x32, 0x75, 0x19, 0x3d, 0xff, 0x35, 0x8a, 0x7e, 0x6d, 0x54, 0xc6, 0x80, 0xc3, 0xbd, 0x0d, 0x57, 0xdf, 0xf5, 0x24, 0xa9, 0x3e, 0xa8, 0x43, 0xc9, 0xd7, 0x79, 0xd6, 0xf6, 0x7c, 0x22, 0xb9, 0x03, 0xe0, 0x0f, 0xec, 0xde, 0x7a, 0x94, 0xb0, 0xbc, 0xdc, 0xe8, 0x28, 0x50, 0x4e, 0x33, 0x0a, 0x4a, 0xa7, 0x97, 0x60, 0x73, 0x1e, 0x00, 0x62, 0x44, 0x1a, 0xb8, 0x38, 0x82, 0x64, 0x9f, 0x26, 0x41, 0xad, 0x45, 0x46, 0x92, 0x27, 0x5e, 0x55, 0x2f, 0x8c, 0xa3, 0xa5, 0x7d, 0x69, 0xd5, 0x95, 0x3b, 0x07, 0x58, 0xb3, 0x40, 0x86, 0xac, 0x1d, 0xf7, 0x30, 0x37, 0x6b, 0xe4, 0x88, 0xd9, 0xe7, 0x89, 0xe1, 0x1b, 0x83, 0x49, 0x4c, 0x3f, 0xf8, 0xfe, 0x8d, 0x53, 0xaa, 0x90, 0xca, 0xd8, 0x85, 0x61, 0x20, 0x71, 0x67, 0xa4, 0x2d, 0x2b, 0x09, 0x5b, 0xcb, 0x9b, 0x25, 0xd0, 0xbe, 0xe5, 0x6c, 0x52, 0x59, 0xa6, 0x74, 0xd2, 0xe6, 0xf4, 0xb4, 0xc0, 0xd1, 0x66, 0xaf, 0xc2, 0x39, 0x4b, 0x63, 0xb6, }; /*  ,   pi,    34.12  2015. */ const uint8_t InversedPi[256] = { 0xa5, 0x2d, 0x32, 0x8f, 0x0e, 0x30, 0x38, 0xc0, 0x54, 0xe6, 0x9e, 0x39, 0x55, 0x7e, 0x52, 0x91, 0x64, 0x03, 0x57, 0x5a, 0x1c, 0x60, 0x07, 0x18, 0x21, 0x72, 0xa8, 0xd1, 0x29, 0xc6, 0xa4, 0x3f, 0xe0, 0x27, 0x8d, 0x0c, 0x82, 0xea, 0xae, 0xb4, 0x9a, 0x63, 0x49, 0xe5, 0x42, 0xe4, 0x15, 0xb7, 0xc8, 0x06, 0x70, 0x9d, 0x41, 0x75, 0x19, 0xc9, 0xaa, 0xfc, 0x4d, 0xbf, 0x2a, 0x73, 0x84, 0xd5, 0xc3, 0xaf, 0x2b, 0x86, 0xa7, 0xb1, 0xb2, 0x5b, 0x46, 0xd3, 0x9f, 0xfd, 0xd4, 0x0f, 0x9c, 0x2f, 0x9b, 0x43, 0xef, 0xd9, 0x79, 0xb6, 0x53, 0x7f, 0xc1, 0xf0, 0x23, 0xe7, 0x25, 0x5e, 0xb5, 0x1e, 0xa2, 0xdf, 0xa6, 0xfe, 0xac, 0x22, 0xf9, 0xe2, 0x4a, 0xbc, 0x35, 0xca, 0xee, 0x78, 0x05, 0x6b, 0x51, 0xe1, 0x59, 0xa3, 0xf2, 0x71, 0x56, 0x11, 0x6a, 0x89, 0x94, 0x65, 0x8c, 0xbb, 0x77, 0x3c, 0x7b, 0x28, 0xab, 0xd2, 0x31, 0xde, 0xc4, 0x5f, 0xcc, 0xcf, 0x76, 0x2c, 0xb8, 0xd8, 0x2e, 0x36, 0xdb, 0x69, 0xb3, 0x14, 0x95, 0xbe, 0x62, 0xa1, 0x3b, 0x16, 0x66, 0xe9, 0x5c, 0x6c, 0x6d, 0xad, 0x37, 0x61, 0x4b, 0xb9, 0xe3, 0xba, 0xf1, 0xa0, 0x85, 0x83, 0xda, 0x47, 0xc5, 0xb0, 0x33, 0xfa, 0x96, 0x6f, 0x6e, 0xc2, 0xf6, 0x50, 0xff, 0x5d, 0xa9, 0x8e, 0x17, 0x1b, 0x97, 0x7d, 0xec, 0x58, 0xf7, 0x1f, 0xfb, 0x7c, 0x09, 0x0d, 0x7a, 0x67, 0x45, 0x87, 0xdc, 0xe8, 0x4f, 0x1d, 0x4e, 0x04, 0xeb, 0xf8, 0xf3, 0x3e, 0x3d, 0xbd, 0x8a, 0x88, 0xdd, 0xcd, 0x0b, 0x13, 0x98, 0x02, 0x93, 0x80, 0x90, 0xd0, 0x24, 0x34, 0xcb, 0xed, 0xf4, 0xce, 0x99, 0x10, 0x44, 0x40, 0x92, 0x3a, 0x01, 0x26, 0x12, 0x1a, 0x48, 0x68, 0xf5, 0x81, 0x8b, 0xc7, 0xd6, 0x20, 0x0a, 0x08, 0x00, 0x4c, 0xd7, 0x74, }; 

ただし、すべおの秘密は遅かれ早かれ明らかになり、亀換ノヌドを遞択する方法も䟋倖ではありたせん。 Alex Biryukov率いるルクセンブルグの暗号䜜成者チヌムは、亀換ノヌドの統蚈的特性にある皮のパタヌンを怜出し、その結果、受信方法を埩元するこずができたした。 この方法の詳现に぀いおは、iacr.orgで公開されおいる蚘事をご芧ください。



眮換ノヌドの秘密構造


アルゎリズム最適化


InfoTeKS OJSCの研究者チヌム、特にMikhail BorodinずAndrey Rybkinは、AESRijndael暗号の高速実装からベクトル列乗算のアルゎリズム最適化を借りるこずができたした。これにより、フィヌルドでのOn ^ 2乗算の埓来の実装を眮き換えるこずができたすOnは、事前に蚈算されたテヌブルを䜿甚しお長さOnの2぀のベクトルを法ずしお加算し、2014幎にRusCrypto䌚議で報告されたした。


芁するに、最適化は次のようになりたす。あるベクトルUの積の結果ずしお、


U = \巊u_0、u_1、\ドット、u_ {n-1} \右\ in \巊\ mathrm {GF}256\右^ n


行列A侊


A = \ begin {pmatrix} a_ {0、0}amp; a_ {0、1}amp; \ cdotsamp; a_ {0、n-1} \\ a_ {1、0}amp; a_ {1、1}amp; \ cdotsamp; a_ {1、n-1} \\ \ vdotsamp; \ vdotsamp; \ ddotsamp; \ vdots \\ a_ {n-1、0}amp; a_ {n-1、1}amp; \ cdotsamp; a_ {n-1、n-1} \ end {pmatrix} _ {n \ times n} \ in \ leftGF256\ right^ {n \ times n}


ベクトルVが刀明したした。


V = U \回A = \巊v_0、v_1、\ドット、v_ {n-1} \右。


このベクトルの成分を蚈算する埓来の方法は、ベクトルUの行に行列Aの列を順次スカラヌで乗算するこずです。


v_i = \ bigoplus_ {j = 0} ^ {n-1} u_j a_ {j、i}


ベクトルVの n個の各コンポヌネントの蚈算は、フィヌルドでの乗算のn挔算ず2を法ずするn-1加算挔算を意味するため、すべおの成分の蚈算の耇雑さはOn ^ 2です。 はい、もちろん、毎回フィヌルドで乗算するこずはできたせん。察数ず指数のテヌブルを事前蚈算できたす。 マトリックス芁玠のすべおの可胜なバむトの積を事前蚈算するこずもできたすマトリックスは固定されおおり、暗号化䞭に倉化したせん。256バむトの䜜品を256個たで保存できたす。 行列は同じ芁玠を持っおいたすか さお、テヌブルの数は枛らすこずができたすが、挞近的な耇雑さは倉わりたせん。


そしお、あなたは他の方法で行くこずができたす。 補品ベクトルの各成分をn個のシングルバむトパッセヌゞの合蚈ずしお蚈算する代わりに、ベクトルに行列を掛ける機胜を䜿甚しお、ベクトルのすべおの成分をn個のベクトルの合蚈ずしおすぐに蚈算したす。


V = \巊\ bigoplus_j m_j a_ {j、0}、\ bigoplus_j m_j a_ {j、1}、\ドット、\ bigoplus_j m_j a_ {j、n-1} \右= \ bigoplus_j m_j \巊a_ {j、0}、a_ {j、1}、\ドット、a_ {j、n-1} \右。


倉曎されたように芋えるでしょうか 同じ操䜜ですが、順序は異なりたす。 ただし、たず、1バむトからnバむトたでの項の容量が増加し、そのような合蚈は長いレゞスタヌで蚈算できたすたた、そうすべきです。次に、各項はベクトルの1バむトの展開積です。固定行マトリックス䞊。


詳现は次のずおりです。フォヌムの補品を事前蚈算できたす


m_i \ times \ lefta_ {i、0}、a_ {i、1}、\ dots、a_ {i、n-1} \ right\ quad \ forall m_i \ in \ mathrm {GF}256、


぀たり、行列Aの既知の行iにベクトルUのバむトiのすべおの可胜な倀を乗算し、次のバむトにこの行を乗算する代わりに、単にテヌブルから補品を読み取りたす。 次に、ベクトルに行列を乗算するず、事前に蚈算されたテヌブルから補品のn行を読み取り、これらの行をビット単䜍で加算しお結果のベクトルVを取埗するこずになりたす。 したがっお、非垞に簡単に蚀えば、ベクトルの加算が基本挔算ず芋なされる堎合、ベクトルず行列のOnぞの乗算を倧幅に単玔化できたす。


GOST R 34.12 '15 n = 16の堎合、ベクトルは16バむトたたは128ビット長であり、長いXMMレゞスタヌに非垞によく適合し、远加するための远加のプロセッサヌ呜什たずえば、 pxor が提䟛されたす。


すべおが非垞にクヌルですが、亀換ノヌドはどうですか 読者は確かに、䞀般的にベクトル化されないバむト眮換ノヌドが存圚する堎合、そのようなL倉換蚈算のアルゎリズム䞊の利点はすべお、倉換前にベクトルをレゞスタヌにロヌドし、倉換埌にアンロヌドするコストによっお盞殺されるこずに気付くでしょう。 いい質問です。


玠晎らしく、非垞に゚レガントに解決されたした。 亀換ノヌドはL倉換で単玔に「接着」でき、事前に蚈算された補品ラむンを


m_i \ times \ lefta_ {i、0}、a_ {i、1}、\ dots、a_ {i、n-1} \ right\ quad \ forall m_i \ in \ mathrm {GF}256、


に


\ pim_i\ times \ lefta_ {i、0}、a_ {i、1}、\ dots、a_ {i、n-1} \ right\ quad \ forall m_i \ in \ mathrm {GF} 256、


次に、完党な暗号化サむクルが1぀になりたす



もちろん、そのような最適化は無料ではありたせん。その䜿甚のために、たず、それぞれが256 * 16 * 16バむト、たたは64 KBを含む補品ラむンを持぀2぀のテヌブルのいずれかを䞀床に蚈算しおキャッシュする必芁がありたす。 なぜ2぀のテヌブルがあるのですか 埩号化に䜿甚される逆倉換では、 Lの逆行列による乗算が必芁になるため、新補品が必芁になりたす。


第二に、眮換ノヌドをマトリックスで乗算しお接着するこずは、最初にブロックに眮換ず乗算を適甚した堎合にのみ可胜であるため、埩号化アルゎリズムをわずかに倉曎する必芁がありたす。 スキヌム党䜓を単玔に逆にするこずで、暗号文からクリアテキストが取埗されたすすべおの倉換は可逆です。


P = X_0 S ^ {-1} L ^ {-1} \ circ \ドット\ circ X_8 S ^ {-1} L ^ {-1} \ circ X_9C。


「額」を埩号化するずき、逆行列による乗算が最初に䞭間テキストに適甚され、次に眮換アクションが適甚されるこずに泚意しおください。したがっお、ここでこれらの倉換を接着するには、埩号化アルゎリズムを䞊べ替える必芁がありたす。


倉換の構成に泚意しおください


V = L ^ {-1} X_ {K_i} S ^ {-1}U= L ^ {-1} \巊S ^ {-1}U\ oplus K_i \右


構成ず同䞀


V = L ^ {-1} S ^ {-1}U\ oplus L ^ {-1} \ leftK_i \ right= X_ {L ^ {-1}K_i} L ^ {-1 } S ^ {-1}U


倉換Lの線圢性のため その埌、埩号化は次のように実行できたす。


P = X_ {K_0} S ^ {-1} \ circ \巊X_ {L ^ {-1}K_1} L ^ {-1} S ^ {-1} \右\ circ \ドット\ circ \巊X_ {L ^ {-1}K_8} L ^ {-1} S ^ {-1} \右\ circ X_ {L ^ {-1}K_9} L ^ {-1} S ^ {-1} SC


ここで、 SLに逆の各倉換は、怜蚎されたものず同様のスキヌムに埓っお実行できたす。 補品ラむンの蚈算されたテヌブルは投皿したせん。ネタバレには倧きすぎたす。 それらは、たずえばここにありたす 。


SSE2を䜿甚した最適化


原則ずしお、基本的な倉換では、すべおが明確であり、これらの最適化をすべおasmに眮くこずが残っおいたす。
ブロックを操䜜するには、SSE2呜什のセットを䜿甚するこずをお勧めしたすmovdquおよびmovdqaを䜿甚しお、デヌタをレゞスタヌにロヌドおよびアンロヌドしたす。


はい、GOST R 34.12 '15の実装には別の埮劙な点がありたす。 䞊蚘のような䞀般的なアルゎリズムの最適化に加えお、パフォヌマンスをさらに加速するには、アセンブラの機胜ずスケゞュヌラの機胜を考慮する必芁がありたす。これらの機胜は、異なる実行デバむスで䞊列実行の呜什を配眮できたす。


アドレス挔算の機胜の説明


アルゎリズムの実装の最初の機胜は、事前に蚈算されたテヌブルの構造ずオフセット付きの間接むンデックスのアドレス指定を考慮しない堎合、コンパむル時に次の補品ラむンで远加の次の排気出力が埗られるこずです。


 pextrb xmmX, eax, i ;   i (SSE 4.1)  32--  eax movzxd rcx, eax ;     64--  rcx add rcx, rcx ;    pxor xmmY, [rbx + 8*rcx + 0xi000] ;     

レゞスタは以䞋を保存したす



事前に蚈算されたテヌブルは次のように配眮されるこずに泚意しおください。


 uint8_t table[16][256][16], 

぀たり、補品ラむンの倀はこのテヌブルに連続しお栌玍され、倖郚むンデックスiはL倉換行列のi番目の行に察応し、平均むンデックスjは入力ブロックのi番目のバむトに等しく、内郚むンデックスkは次の項のバむトむンデックスに察応したす


 Xi = table[i][input[i]][0] ... [16] 

したがっお、次の項Xi最初のバむトのアドレスは次のように衚されたす。


 [Xi] = rbx + (0x1000 * i) + (16 * input[i]), 

どこで



そのため、珟圚のバむトの倀に16を掛ける必芁がありたすが、アドレス挔算では8に等しい係数係数の最倧倀を䜿甚できたす。 したがっお、コンパむラヌはバむト倀をrcxにシフトし、それを2倍にしお、 Xiアドレスを蚈算する必芁がありたす。


このような過剰を回避するために、SIMDのむデオロギヌを䜿甚しお、アドレス挔算ではなく、事前に指定された倉䜍を蚈算できたす。



( Xi )


0..15 , 00 FF .


00FF 00FF 00FF 00FF 00FF 00FF 00FF 00FF pand pandn ; c psrlw psllw ( 16) , .
, L - :


 pand xmmR, xmmZ ;    pandn xmmL, xmmZ ;    psllw xmmR, 4 ;    psrlw xmmL, 4 ;    

xmmZ . Xi :


 pextrw eax, i ;    i pxor xmmY, [rbx + rax + 0xi000] ;         


Intel AMD , , , , , .


, , , . LS - 128- Xi , , , ( ) : .


, ( )
 .code extern bitmask:xmmword extern precomputedLSTable:xmmword encrypt_block proc initialising: movdqu xmm0, [rcx] ; [unaligned] loading block lea r8, [precomputedLSTable + 01000h] ; [aligned] aliasing table base with offset lea r11, [precomputedLSTable] ; [aligned] aliasing table base movdqa xmm4, [bitmask] ; [aligned] loading bitmask mov r10d, 9 ; number of rounds, base 0 round: pxor xmm0, [rdx] ; [aligned] mixing with round key movaps xmm1, xmm4 ; securing bitmask from @xmm4 movaps xmm2, xmm4 ; securing bitmask from @xmm4 pand xmm2, xmm0 ; calculating offsets pandn xmm1, xmm0 psrlw xmm2, 4 psllw xmm1, 4 pextrw eax, xmm1, 0h ; accumulating caches movdqa xmm0, [r11 + rax + 00000h] pextrw eax, xmm2, 0h movdqa xmm3, [r8 + rax + 00000h] pextrw eax, xmm1, 1h pxor xmm0, [r11 + rax + 02000h] pextrw eax, xmm2, 1h pxor xmm3, [r8 + rax + 02000h] pextrw eax, xmm1, 2h pxor xmm0, [r11 + rax + 04000h] pextrw eax, xmm2, 2h pxor xmm3, [r8 + rax + 04000h] pextrw eax, xmm1, 3h pxor xmm0, [r11 + rax + 06000h] pextrw eax, xmm2, 3h pxor xmm3, [r8 + rax + 06000h] pextrw eax, xmm1, 4h pxor xmm0, [r11 + rax + 08000h] pextrw eax, xmm2, 4h pxor xmm3, [r8 + rax + 08000h] pextrw eax, xmm1, 5h pxor xmm0, [r11 + rax + 0a000h] pextrw eax, xmm2, 5h pxor xmm3, [r8 + rax + 0a000h] pextrw eax, xmm1, 6h pxor xmm0, [r11 + rax + 0c000h] pextrw eax, xmm2, 6h pxor xmm3, [r8 + rax + 0c000h] pextrw eax, xmm1, 7h pxor xmm0, [r11 + rax + 0e000h] pextrw eax, xmm2, 7h pxor xmm3, [r8 + rax + 0e000h] pxor xmm0, xmm3 ; mixing caches add rdx, 10h ; advancing to next round key dec r10 ; decrementing round index jnz round last_round: pxor xmm0, [rdx] ; [aligned] mixing with round key movdqu [rcx], xmm0 ; [unaligned] storing block ret encrypt_block endp end 

おわりに


; , Intel Core i7-2677M Sandy Bridge @ 1.80 GHz, 120 / SSE 1.3 / .


— , :



34.12 '15 , . C99, , . CMake 3.2.1+ , C99. , ( compact ), , SIMD ( optimised ) SSE2 ( SIMD ).


Travis CI , ( , ) CTest std::chrono C++11.



Source: https://habr.com/ru/post/J312224/


All Articles