Have an amazing solution built in RAD Studio? Let us know. Looking for discounts? Visit our Special Offers page!
C++RAD Studio

C++Builderでビットシフトを使用したファイルのエンコード/デコードを行うには?

pexels-negative-space-97077-2

この記事は、Yılmaz Yörü氏のhttps://blogs.embarcadero.com/encoding-and-decoding-files-in-c-builder-by-using-bit-shifting/の抄訳です

最速のデータ符号化(エンコード)および復号化(デコード)方式とは?データを保護するための最速の方法は何ですか?データやファイルのエンコードやデコードにシフトを使うことはできますか?文字列やバイナリデータにシフトを使うことはできるのか?

このブログでは、それらの疑問にお答えいたします。

ビットとビットワイズ演算

ビットは、コンピュータやデジタル通信における情報の最も基本的な単位です。実際には、すべての演算子は主にビット演算に基づいており、「ビットワイズ演算子」とも呼ばれます。

コンピュータプログラミングでは、ビット文字列、ビット配列、または2進数(ビット文字列とみなす)を、個々のビット、1、0のレベルで操作することをビットワイズ演算と言います。ビット演算は、高レベルの算術演算の基本であり、プロセッサが直接サポートしているため、高速でシンプルな動作を実現しています。ほとんどのビット演算は、結果が入力オペランドの1つを置き換える 2オペランド命令として表されます。

このようなコンピュータのマイクロアーキテクチャの基本的な知識があるからこそ、ビット演算子を知っておくことは非常に重要なのです。C言語は最も古いプログラミング言語の一つで、他のプログラミング言語のオペランドや演算子の多くは、C言語からヒントを得ています。CとC++には同じ演算子があり、ほとんどの演算子は他のプログラミング言語でも同じです。一般的な演算子については、「C++の基礎: 演算子の使い方を学ぶ」をご覧ください。

それでは、ビットシフトとエンコード-デコードの例を見てみましょう。

データのビットシフト

ビット単位のオペランドの1つにビットシフトがあり、左シフトの’<<‘オペランドと右シフトの’>>‘オペランドがあります。ビット演算は、上述のようにコンピュータのマイクロアーキテクチャのため、マシンコードやC++では最も高速な演算です。多くのエンコードおよびデコード方法があり、ハッシュ符号化の方法もあります。最も簡単で高速な符号化(エンコード)方式の一つが「ビットシフトデータ」です。この方法は、データファイルのエンコードおよびデコードに利用できます。

左シフトと右シフト

例えば、cを文字とすると、ビットシフトを利用して以下のように文字のエンコードとデコードを行うことができます。

c = c << 1; // Encoding with Left Bit Shifting
c = c >> 1; // Decoding with Right Bit Shifting

このコード例は、127未満の文字数でうまく機能します。シフトする際に先頭のビットが失われます(左にシフトすると左のビットが、右にシフトすると右のビットが失われる)。これらのビットをすべてバイナリデータに保持するには、循環ビットシフト(Circular Bit Shifting)を行う必要があります。

循環左シフトと循環右シフト

循環ビットシフトを使用すれば、データのエンコードやデコードの際に、ビットを失うことはありません。最大8ビットのうち2ビットをシフトしたい場合は、以下のように左右の循環ビットシフトを行います。

c =(c << 2)|(c >> (8 - 2); // Encoding with Circular Left 2 Bits Shifting
c =(c >> 2)|(c << (8 - 2); // Decoding with Circular Right 2 Bits Shifting

複雑な循環左シフトと循環右シフト

例えば、(1+i%7)を加えることで、シフトするビット数に複雑性を与えることができます。

c =(c << (1+i%7))|(c >> (8 - (1+i%7)); // Encoding by Circular Left Bits Shifting with Complexity
c =(c >> (1+i%7))|(c << (8 - (1+i%7)); // Decoding by Circular Right Bits Shifting with Complexity

C++Builderでデータファイルをビットシフトする

例えば、C++Builderでデータファイルのエンコードとデコードを行うために、この「複雑な循環ビットシフト法」を使用することができます。C++Builderでこの例を実行するには、

1.C++Builder VCLプロジェクトを新規に作成し、すべてのファイルをプロジェクトフォルダに保存します。

2.TButtonコンポーネントを2つフォーム上に配置し、Button1->Caption = “Encode”、Button2->Caption = “Decode “に変更します。

3. TMemoとTOpenDialogコンポーネントをパレットからドラッグしてフォームに配置します。

4. F12を押してコードモードに切り替え、以下の例のようにコードにヘッダーを追加します。

//---------------------------------------------------------------------------
 
#include <vcl.h>
#include <iostream>
#include <fstream>
#include <string>
#pragma hdrstop
 
#include "Encoding_and_Decoding_Data_File_VCL_Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)  : TForm(Owner)
{
}

5. Button1の「Encode」ボタンをダブルクリックし、OnClickイベントハンドラに以下のような「エンコードファイルを開き、エンコードし、エンコードされたファイルを保存する」コードを実装します。

//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender) 
{
   // ENCODING 
   OpenDialog1->Title = "Choose a File to Encode";
   OpenDialog1->DefaultExt = "";
   OpenDialog1->FileName = "";
   OpenDialog1->Execute();
   if(OpenDialog1->FileName.Length()>0)
   {
	   unsigned char c;   // std::bitset<8> x;
	   unsigned int i=0;
 
	   std::ifstream indata;
	   std::ofstream outdata;
 
	   indata.open(OpenDialog1->FileName.w_str(), std::fstream::binary);
	   if(!indata)
	   {
		  Memo1->Lines->Add("Error: Input file could not be opened");
		  exit(1);
	   }
 
	   outdata.open((OpenDialog1->FileName+".enc").w_str(), std::fstream::binary);
	   if(!outdata)
	   {
		  Memo1->Lines->Add("Error: Output file could not be openedn");
		  indata.close();
		  exit(1);
	   }
 
	   Memo1->Lines->Add("nEncoding..n");
 
	   i=0;
	   while ( !indata.eof() )
	   {
		  c=indata.get();  // get the next char of data  or indata.get();
 
 
		  c =(c << (1+i%7))|(c >> (8 - (1+i%7)));  // Encoding by Circular Left Bit Shifting with Complexity
		  outdata.put(c); // out the encoded char
 
		  i++;
	   }
 
	   indata.close();
	   outdata.close();
 
	   Memo1->Lines->Add("Done! '"+OpenDialog1->FileName+".enc' saved!");
   }
}

6. Button2の「Decode」ボタンをダブルクリックし、OnClickイベントハンドラに以下のような「エンコードファイルを開き、デコードし、デコードされたファイルを保存する」コードを実装します。

//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
   OpenDialog1->Title = "Choose .enc File to Decode";
   OpenDialog1->DefaultExt = "";
   OpenDialog1->FileName ="*.enc";
   OpenDialog1->Execute();
   if(OpenDialog1->FileName.Length()>0)
   {
	   unsigned char c;   // std::bitset<8> x;
	   unsigned int i=0;
 
	   std::ifstream indata;
	   std::ofstream outdata;
 
		  // DECODING mytest.dat to mytest2.txt
	   // ---------------------------------------------------------
	   indata.open(OpenDialog1->FileName.w_str(), std::fstream::binary);
	   if(!indata)
	   {
		  Memo1->Lines->Add("Error: Input file could not be opened");
		  exit(1);
	   }
 
	   outdata.open((OpenDialog1->FileName+".dec").w_str(), std::fstream::binary);
	   if(!outdata)
	   {
		  Memo1->Lines->Add("Error: Output file could not be openedn");
		  indata.close();
		  exit(1);
	   }
 
 
	   i=0;
	   Memo1->Lines->Add("nDecoding..n");
	   while ( !indata.eof() )
	   {
		  c= indata.get();  // get the next char of data
		  //c = c >> 1; // Decoding with Right Bit Shifting
		  c =(c >> (1+i%7))|(c << (8 - (1+i%7)));  // Decoding by Right Bit Shifting with Complexity
		  outdata.put(c); // out the encoded char
 
		  i++;
	   }
 
	   indata.close();
	   outdata.close();
 
	   Memo1->Lines->Add("Done! '"+OpenDialog1->FileName+".dec' saved!");
   }
}

7. F9を押すと、プロジェクトをビルドし、デバッグ実行します。これでエンコードするファイルを選択し、*.encファイルをエンコードして、*.decファイルとしてデコードすることができます。

encodedecode-9801634-2

このビットシフト手法を使用して、データ、ユーザー名、パスワードなどの機密事項を保護することができます。また、このエンコードされたデータを暗号化ハッシュ関数(SHA、SHA2、MD5、BobJenkinsなど)を使ってハッシュ化することもできます。詳しくは「WindowsのモダンC++で強力な暗号化ハッシュ関数を学ぶ (SHA, SHA2, MD5, BobJenkins)」を参照ください。

RAD Studio 13.2 Florence Now Available! Kai 1.1.1 Now Available! What's Coming in RAD Studio 13.2 Florence

Reduce development time and get to market faster with RAD Studio, Delphi, or C++Builder.
Design. Code. Compile. Deploy.

Start Free Trial   Upgrade Today

   Free Delphi Community Edition   Free C++Builder Community Edition

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

IN THE ARTICLES