ページ 1 / 1
テキストファイルの暗号化の処理で行き詰っています
Posted: 2014年4月16日(水) 21:01
by elle
こんばんは。
今私は、テキストをシーザー方式で暗号化するプログラムを作っています。
ただし文字をずらすのではなく、文字コードをずらしています。
純粋に定数分だけずらすことはできたので、ずらす値を乱数で取得する、ちょっとした改良版のようなものを作っています。
同じシード値を与えて逆方向にずらせば平文が得られる形です。
プログラムとしては、標準入力でファイルパスを取得し、(encrypted)という名前を付加した新規ファイルに暗号化結果を書き込み、
もしパスに(encrypted)が含まれていれば復号処理にする流れにしました。
コード:
#include <iostream>
#include <fstream>
#include <string>
#include <typeinfo>
#include <algorithm>
#include <random>
#include <iomanip>
using namespace std;
const string ENCRYPTION_SUFFIX("(encrypted)");
const string DECRYPTION_SUFFIX("(decrypted)");
enum class Operation{
Encryption,
Decryption
};
int main()
{
string fileInPath, fileOutPath;
cout.setf(ios_base::hex, ios_base::basefield);
cout.setf(ios_base::showbase);
mt19937 mt19937(0xffff);
uniform_int_distribution<> dist(1, 3);
while (true){
// パス取得(stdin)
cout << "type the path of the file you want to encrypt (you can also Drag and Drop the file).\n"
"type \"0\" to quit this program.\n";
getline(cin, fileInPath);
// 0が入力されれば終了
if (fileInPath == "0")
break;
// ""をはずす
const auto endIt = remove(fileInPath.begin(), fileInPath.end(), '\"');
fileInPath.erase(endIt, fileInPath.end());
// ファイル名に(encrypted)が含まれていれば、復号化処理にする
const Operation operation = fileInPath.find(ENCRYPTION_SUFFIX, fileInPath.find_last_of("\\/")) != string::npos ? Operation::Decryption : Operation::Encryption;
try{
// 入力元oepn
ifstream filein(fileInPath.c_str());
filein.exceptions(ifstream::badbit);
// 出力先open(サフィックス追加)
fileOutPath = fileInPath;
fileOutPath.insert(fileOutPath.rfind("."), operation == Operation::Encryption ? ENCRYPTION_SUFFIX : DECRYPTION_SUFFIX);
ofstream fileout(fileOutPath.c_str());
fileout.exceptions(ofstream::badbit);
// 暗号化(シーザー)
string buf;
while (getline(filein, buf)){
// cout << buf << "\n";
if (operation == Operation::Encryption && ofstream::eofbit)
buf += "\n";
for (auto&& elem : buf){
// cout << setw(10) << static_cast<int>(elem) << " to ";
elem += operation == Operation::Encryption ? dist(mt19937) : dist(mt19937) * -1;
// cout << setw(10) << static_cast<int>(elem) << "\n";
}
// 0x5cがある場合はエスケープされないように直後に追加する
size_t pos = 0;
while ((pos = buf.find('\\', pos)) != string::npos){
buf.insert(pos++, "\\");
}
fileout << buf;
// cout << buf << "\n";
}
}
catch (exception& e){
cerr << "[ " << typeid(e).name() << " ] exception was thrown because of [ " << e.what() << " ]\n" << endl;
return -1;
}
clog << (operation == Operation::Encryption ? "Encryption" : "Decryption") << " is successfully completed.\n\n";
}
clog << "end program..." << endl;
return 0;
}
このプログラムに対し、
このようなテキストファイルをあてがうと、2行目を読み込んだ時に、(プログラムの)75行目のwhile文で無限ループに陥ってしまいます。(永久に'\\'が見つかってしまいposがどんどん増えていきます)
コメント部分はデバッグ表示用なのですが、はずして確かめてみると、
やはり暗号化した結果0x5cが出現したときに問題が起きているように思います(これが含まれないテキストは正常に暗号化・復号化できました)。
posの進め方が問題なのかと思い、posを前置にしたり、インクリメント自体なしも試したのですが、動作は変わらず、
+2や、前置インクリメントしてその後別に+1だと止まらなくはなったものの正しい結果が得られなくなりました。
(このようになります)
(ちなみに75行目からのwhile文なしの場合はこうなりました)
insertした後で位置を進めておけば、ちょうど挿入した直後の位置になるかと思ったのですが、意図したとおりになりません…。
どのようにするのが良いでしょうか?
Re: テキストファイルの暗号化の処理で行き詰っています
Posted: 2014年4月16日(水) 21:09
by みけCAT
elle さんが書きました:posの進め方が問題なのかと思い、posを前置にしたり、インクリメント自体なしも試したのですが、動作は変わらず、
+2や、前置インクリメントしてその後別に+1だと止まらなくはなったものの正しい結果が得られなくなりました。
このコードを提示できますか?
これではうまくいかない、ということですか?
コード:
#include <cstdio>
#include <string>
using std::string;
int main(void) {
std::string buf="新しいキーワード\\n";
size_t pos = 0;
while ((pos = buf.find('\\', pos)) != string::npos){
buf.insert(pos, "\\");
pos+=2;
}
puts(buf.c_str());
return 0;
}
Re: テキストファイルの暗号化の処理で行き詰っています
Posted: 2014年4月16日(水) 21:19
by h2so5
根本的な問題として、暗号化時に文字が改行コードに変換されてしまった場合はどうするのでしょうか?
復号するときにgetlineで正常に読み込めないと思うのですが。
Re: テキストファイルの暗号化の処理で行き詰っています
Posted: 2014年4月16日(水) 21:30
by みけCAT
そもそも「0x5cがある場合はエスケープされないように直後に追加する」という処理は必要なのですか?
蛇足ではないですか?
Re: テキストファイルの暗号化の処理で行き詰っています
Posted: 2014年4月16日(水) 21:45
by elle
みけCATさん
あ…こんな簡単なことを見落としていたとは…
たしかにそのstringだと自分のコードでは無限ループになりますね。(そしてその状態が出現して無限ループになっていたのですね)
そうしますと、文字コードでずらすのは困難で、アルファベットをずらすようにするべきでしょうか…
h2so5さん
改行コードに変換された場合でも、そこでgetlineが区切られますので、
読み込んだ後に改行コードを末尾に追加することで(63~64行目)元の文を復元していますので、
この点に関しては問題はない…つもりです。
Re: テキストファイルの暗号化の処理で行き詰っています
Posted: 2014年4月16日(水) 21:49
by elle
みけCATさん
エスケープなしで、No.1の2番目ような結果になってしまったので、
このページなどを見て入れた方がいいのかと思ったのですが、
入れても入れなくても正しい結果にならないということは別の原因が有るのかもしれません…。
定数でずらす方でこの関連をもう少し試してみます。
Re: テキストファイルの暗号化の処理で行き詰っています
Posted: 2014年4月16日(水) 22:19
by elle
みけCATさん
すいません、早とちりしてました。
みけCATさんがNo.2で提示されたコードは正確に結果が出力されますね。
失礼しました。
何パターンか試してみましたが、日本語との絡みも含めて0x5c(\)もそのまま表示できるように思えましたので、
おっしゃる通りエスケープシーケンスの追加は蛇足でした。
別の箇所に原因が有るのでしょうか…。
► スポイラーを表示
コード:
#include <iostream>
#include <fstream>
#include <string>
#include <typeinfo>
#include <algorithm>
#include <random>
#include <iomanip>
using namespace std;
const int ENCRYPTION_OFFSET = 1;
const string ENCRYPTION_SUFFIX("(encrypted)");
const string DECRYPTION_SUFFIX("(decrypted)");
enum class Operation{
Encryption,
Decryption
};
int main()
{
string fileInPath, fileOutPath;
cout.setf(ios_base::hex, ios_base::basefield);
cout.setf(ios_base::showbase);
mt19937 mt19937(0xffff);
uniform_int_distribution<> dist(1, 3);
while (true){
// パス取得(stdin)
cout << "type the path of the file you want to encrypt (you can also Drag and Drop the file).\n"
"type \"0\" to quit this program.\n";
getline(cin, fileInPath);
// 0が入力されれば終了
if (fileInPath == "0")
break;
// ""をはずす
const auto endIt = remove(fileInPath.begin(), fileInPath.end(), '\"');
fileInPath.erase(endIt, fileInPath.end());
// ファイル名に(encrypted)が含まれていれば、復号化処理にする
const Operation operation = fileInPath.find(ENCRYPTION_SUFFIX, fileInPath.find_last_of("\\/")) != string::npos ? Operation::Decryption : Operation::Encryption;
try{
// 入力元oepn
ifstream filein(fileInPath.c_str());
filein.exceptions(ifstream::badbit);
// 出力先open
fileOutPath = fileInPath;
fileOutPath.insert(fileOutPath.rfind("."), operation == Operation::Encryption ? ENCRYPTION_SUFFIX : DECRYPTION_SUFFIX);
ofstream fileout(fileOutPath.c_str());
fileout.exceptions(ofstream::badbit);
// 暗号化(シーザー)
string buf;
while (getline(filein, buf)){
if (operation == Operation::Encryption && ofstream::eofbit)
buf += "\n";
for (auto&& elem : buf){
elem += operation == Operation::Encryption ? dist(mt19937) : dist(mt19937) * -1;
// elem += operation == Operation::Encryption ? ENCRYPTION_OFFSET : -ENCRYPTION_OFFSET;
}
fileout << buf;
}
}
catch (exception& e){
cerr << "[ " << typeid(e).name() << " ] exception was thrown because of [ " << e.what() << " ]\n" << endl;
return -1;
}
clog << (operation == Operation::Encryption ? "Encryption" : "Decryption") << " is successfully completed.\n\n";
}
clog << "end program..." << endl;
return 0;
}
このコードに対し、
このテキストを暗号化させると、定数(67行目を消して68行目を使用)の場合は正常に復号化され、乱数の場合は
こうなってしまいます…。
うーん…、原因が見当もつきません…。
Re: テキストファイルの暗号化の処理で行き詰っています
Posted: 2014年4月16日(水) 22:23
by みけCAT
h2so5 さんが書きました:根本的な問題として、暗号化時に文字が改行コードに変換されてしまった場合はどうするのでしょうか?
復号するときにgetlineで正常に読み込めないと思うのですが。
ここで指摘されているとおり、'\'より改行コード(\x0d,\x0a)をエスケープするべきです。
もちろん、復号化するときは文字コードをずらす前にエスケープを元に戻さないといけません。
また、もちろんエスケープに'\'を使うなら、'\'もエスケープしないといけません。
【補足】
暗号化: 入力→ずらす→エスケープ→出力
復号化: 入力→エスケープ解除→逆にずらす→出力
Re: テキストファイルの暗号化の処理で行き詰っています
Posted: 2014年4月19日(土) 14:56
by ジャガ
elle さんが書きました:
何パターンか試してみましたが、日本語との絡みも含めて0x5c(\)もそのまま表示できるように思えましたので、
試されたパターンに水平タブ(0x09)を含んだものはありますか?
こうなってしまいます…。
うーん…、原因が見当もつきません…。
どのような手順で復号化しましたか?
起動>暗号化>終了(0入力)>起動>復号化
という手順ならとりあえず(h2so5さんのご指摘のケースを除き)復号化できそうな気がします。
Re: テキストファイルの暗号化の処理で行き詰っています
Posted: 2014年4月19日(土) 15:02
by elle
みけCATさん
ありがとうございます。返信が遅れてすいません。
ご意見を元にプログラムを改良しました。
(h2so5さん、見当違いな返信をしてしまいすいませんでした。)
► スポイラーを表示
コード:
#include <iostream>
#include <fstream>
#include <string>
#include <typeinfo>
#include <algorithm>
#include <random>
#include <iomanip>
using namespace std;
// constants
const int ENCRYPTION_OFFSET = 1;
const string ENCRYPTION_SUFFIX("(encrypted)");
const string DECRYPTION_SUFFIX("(decrypted)");
const string NL_ESC("\\n");
const string CR_ESC("\\r");
const string ESC_ESC("\\\\");
// global variables
static ifstream filein;
static ofstream fileout;
static string fileInPath, fileOutPath;
static mt19937 randmt(0xffff);
static uniform_int_distribution<> dist(1, 255);
void Encryption()
{
// 入力元oepn
filein.open(fileInPath.c_str());
// 出力先open
fileOutPath = fileInPath;
fileOutPath.insert(fileOutPath.rfind("."), ENCRYPTION_SUFFIX);
fileout.open(fileOutPath.c_str());
// 暗号化
string buf;
while (getline(filein, buf)){
buf += "\n";
// 暗号化
for (auto&& elem : buf){
elem += dist(randmt);
}
// \は\\に
size_t pos = 0;
while ((pos = buf.find("\\", pos)) != string::npos){
buf.replace(pos, 1, ESC_ESC);
pos += 2;
}
// NLとCRはエスケープして書き込む
pos = 0;
while ((pos = buf.find("\n", pos)) != string::npos){
buf.replace(pos++, 1, NL_ESC);
}
pos = 0;
while ((pos = buf.find("\r", pos)) != string::npos){
buf.replace(pos++, 1, CR_ESC);
}
// 書き込む
fileout << buf;
}
}
void Decryption()
{
// 入力元oepn
filein.open(fileInPath.c_str());
// 出力先open
fileOutPath = fileInPath;
fileOutPath.insert(fileOutPath.rfind("."), DECRYPTION_SUFFIX);
fileout.open(fileOutPath.c_str());
// 暗号化
string buf;
while (getline(filein, buf)){
size_t pos = 0;
// NLとCRを戻す
pos = 0;
while ((pos = buf.find(NL_ESC, pos)) != string::npos){
// 直前にも\\があればそれは素の文字
if (buf[pos - 1] == '\\' && buf[pos - 2] == '\\'){
pos += 2;
continue;
}
buf.replace(pos++, NL_ESC.size(), "\n");
}
pos = 0;
while ((pos = buf.find(CR_ESC, pos)) != string::npos){
if (buf[pos - 1] == '\\' && buf[pos - 2] == '\\'){
pos += 2;
continue;
}
buf.replace(pos++, CR_ESC.size(), "\r");
}
// \\は\に
pos = 0;
while ((pos = buf.find(ESC_ESC, pos)) != string::npos){
buf.replace(pos, ESC_ESC.size(), "\\");
pos += 2;
}
// 復号化
for (auto&& elem : buf){
elem += dist(randmt) * -1;
}
// 書き込む
fileout << buf;
}
}
int main()
{
cout.setf(ios_base::hex, ios_base::basefield);
cout.setf(ios_base::showbase);
filein.exceptions(ifstream::badbit);
fileout.exceptions(ofstream::badbit);
void(*Management[])() = {Encryption, Decryption};
while (true){
// パス取得(stdin)
cout << "type the path of the file you want to encrypt (you can also Drag and Drop the file).\n"
"type \"0\" to quit this program.\n";
getline(cin, fileInPath);
// 0が入力されれば終了
if (fileInPath == "0")
break;
// ""をはずす
const auto endIt = remove(fileInPath.begin(), fileInPath.end(), '\"');
fileInPath.erase(endIt, fileInPath.end());
// ファイル名に(encrypted)が含まれていれば、復号化処理にする
const bool toBeDecrypted = fileInPath.find(ENCRYPTION_SUFFIX, fileInPath.find_last_of("\\/")) != string::npos;
try{
// 必要な方を呼び出し
Management[toBeDecrypted]();
}
catch (exception& e){
cerr << "[ " << typeid(e).name() << " ] exception was thrown because of [ " << e.what() << " ]\n" << endl;
return -1;
}
clog << (toBeDecrypted ? "Decryption" : "Encryption") << " is successfully completed.\n\n";
}
clog << "end program..." << endl;
return 0;
}
このコードでの暗号化・復号化は以下のようになりました。
► スポイラーを表示
new.txt
コード:
LEAVES OF GRASS
By Walt Whitman
Come, said my soul,
Such verses for my Body let us write, (for we are one,)
That should I after return,
Or, long, long hence, in other spheres,
There to some group of mates the chants resuming,
(Tallying Earth's soil, trees, winds, tumultuous waves,)
Ever with pleas'd smile I may keep on,
Ever and ever yet the verses owning?as, first, I here and now
Signing for Soul and Body, set to them my name,
Walt Whitman
________________________________________
new(encrypted).txt(5個のヌルを含む)
コード:
・・キ:アェ・<・T・誼O味・・f・g・yJBZ2ヤfンLYム ムォ cユSg1<Uム」2vlワヌ∫?.zテbセp2^ス・|綫・悩・q婪・・・Xp・|Aヌ゚蟹サxニ・ク榮0(・N#CェHケセマメ(ェ\\ヲ船T"kwノ}エⅥmイナF・レ・>醗t・Qト&ッqN・クZ錞qo$・ン聖>ョ鯏ヒクク体ネ9:Cイ泥チヌ`曹I(ヘノ\r張kトタd・hヲjニ遲ヌ7オwワyッV・Nラo蓬UケFOー、uhチo馭!5X悴<e昱l便}ソ沚,ラdHヨ・!エJ/TETc欲・.・Kxl;E・$埓・・F4ルケクア7「lォ゙炊=サg逞・核・1タ・ヨ{・・・9チ梯x・編Sッ・憊5・ァo8ト餝 Fニ#・渊 #}・B鋼キrA・[・x。.SW隙ヌレキ・テXM`゚$Rハア羹ヤ?<ハェ\n9・ャ臟釼ク2ユコdm]゙44ァJBD鑈G(6R・+ vアエヤ珵・7j'l
new(encrypted)(decrypted).txt
コード:
LEAVES OF GRASS
By Walt Whitman
Come, said my soul,
Such verses for my Body let us write, (for we are one,)
That should I after r
途中まではほぼ成功したのですが、途中からすっぽり抜けていました。
EOFが関係あるのかと思い、調べたところ
0x1aがEOFとして取り扱われることがあるとの情報があったので、
0x1aもエスケープするようにしたところ、上記のテキストに対しては最後まで正しく復号されました。
しかし、これがもっと長いファイルになると、
例えば0123456789\nを1行としてこれが1000行あるファイルだと、途中から全く違う文字に復号されてしまいます。
下記のようなコードにしてdebug print部でブレークさせてみると、
► スポイラーを表示
コード:
#include <iostream>
#include <fstream>
#include <string>
#include <typeinfo>
#include <algorithm>
#include <random>
#include <iomanip>
#include <cctype>
using namespace std;
// constants
const int ENCRYPTION_OFFSET = 1;
const string ENCRYPTION_SUFFIX("(encrypted)");
const string DECRYPTION_SUFFIX("(decrypted)");
const string NL_ESC("\\n");
const string CR_ESC("\\r");
const string EOF_ESC("\\e");
const string ESC_ESC("\\\\");
// global variables
static ifstream filein;
static ofstream fileout;
static string fileInPath, fileOutPath;
static mt19937 randmt(0xffff);
static uniform_int_distribution<> dist(1, 255);
void Encryption()
{
// 入力元oepn
filein.open(fileInPath.c_str());
// 出力先open
fileOutPath = fileInPath;
fileOutPath.insert(fileOutPath.rfind("."), ENCRYPTION_SUFFIX);
fileout.open(fileOutPath.c_str());
// 暗号化
string buf;
while (getline(filein, buf)){
buf += "\n";
// 暗号化
for (auto&& elem : buf){
elem += dist(randmt);
}
// \は\\に
size_t pos = 0;
while ((pos = buf.find("\\", pos)) != string::npos){
buf.replace(pos, 1, ESC_ESC);
pos += 2;
}
// NLとCRはエスケープして書き込む
pos = 0;
while ((pos = buf.find("\n", pos)) != string::npos){
buf.replace(pos++, 1, NL_ESC);
}
pos = 0;
while ((pos = buf.find("\r", pos)) != string::npos){
buf.replace(pos++, 1, CR_ESC);
}
// EOFもエスケープする
pos = 0;
while ((pos = buf.find("\x1a", pos)) != string::npos){
buf.replace(pos++, 1, EOF_ESC);
}
// 書き込む
fileout << buf;
}
}
void Decryption()
{
// 入力元oepn
filein.open(fileInPath.c_str());
// 出力先open
fileOutPath = fileInPath;
fileOutPath.insert(fileOutPath.rfind("."), DECRYPTION_SUFFIX);
fileout.open(fileOutPath.c_str());
// 暗号化
string buf;
while (getline(filein, buf)){
size_t pos = 0;
// NLとCR、EOFを戻す
pos = 0;
while ((pos = buf.find(NL_ESC, pos)) != string::npos){
// 直前にも\\があればそれは素の文字
if (buf[pos - 1] == '\\' && buf[pos - 2] == '\\'){
pos += 2;
continue;
}
buf.replace(pos++, NL_ESC.size(), "\n");
}
pos = 0;
while ((pos = buf.find(CR_ESC, pos)) != string::npos){
if (buf[pos - 1] == '\\' && buf[pos - 2] == '\\'){
pos += 2;
continue;
}
buf.replace(pos++, CR_ESC.size(), "\r");
}
pos = 0;
while ((pos = buf.find(EOF_ESC, pos)) != string::npos){
if (buf[pos - 1] == '\\' && buf[pos - 2] == '\\'){
pos += 2;
continue;
}
buf.replace(pos++, EOF_ESC.size(), "\x1a");
}
// \\は\に
pos = 0;
while ((pos = buf.find(ESC_ESC, pos)) != string::npos){
buf.replace(pos++, ESC_ESC.size(), "\\");
}
// 復号化
for (auto&& elem : buf){
cout << setw(10) << static_cast<int>(elem) << " to ";
elem += dist(randmt) * -1;
cout << setw(10) << static_cast<int>(elem) << '\n';
if (!isdigit(elem) && elem != '\n'){
cout << "fa" << '\n';
}
}
// 書き込む
fileout << buf;
}
}
int main()
{
cout.setf(ios_base::hex, ios_base::basefield);
cout.setf(ios_base::showbase);
filein.exceptions(ifstream::badbit);
fileout.exceptions(ofstream::badbit);
void(*Management[])() = {Encryption, Decryption};
while (true){
// パス取得(stdin)
cout << "type the path of the file you want to encrypt (you can also Drag and Drop the file).\n"
"type \"0\" to quit this program.\n";
getline(cin, fileInPath);
// 0が入力されれば終了
if (fileInPath == "0")
break;
// ""をはずす
const auto endIt = remove(fileInPath.begin(), fileInPath.end(), '\"');
fileInPath.erase(endIt, fileInPath.end());
// ファイル名に(encrypted)が含まれていれば、復号化処理にする
const bool toBeDecrypted = fileInPath.find(ENCRYPTION_SUFFIX, fileInPath.find_last_of("\\/")) != string::npos;
try{
// 必要な方を呼び出し
Management[toBeDecrypted]();
}
catch (exception& e){
cerr << "[ " << typeid(e).name() << " ] exception was thrown because of [ " << e.what() << " ]\n" << endl;
return -1;
}
clog << (toBeDecrypted ? "Decryption" : "Encryption") << " is successfully completed.\n\n";
}
clog << "end program..." << endl;
return 0;
}
0x5cが2回連続している場所でずれのようなものが発生しているようです。
何が原因なのでしょうか…。
Re: テキストファイルの暗号化の処理で行き詰っています
Posted: 2014年4月19日(土) 15:04
by elle
ジャガさん
ありがとうございます。
水平タブは無かったと思います。
改良したコードでは、No.7の内容は正常に暗号化・復号化できました。
Re: テキストファイルの暗号化の処理で行き詰っています
Posted: 2014年4月19日(土) 17:01
by h2so5
直前のエスケープ文字だけ見ても意味がないですよ。
"\\\\\n" と "\\\\\\n" では\nの解釈が違いますが直前だけ見ても区別できませんよね。
Re: テキストファイルの暗号化の処理で行き詰っています
Posted: 2014年4月19日(土) 23:28
by elle
h2so5さん
あっ、そうでした…。ありがとうございます。
皆さんのアドバイスのおかげで完成しました!
長大なテキストなどでテストして完全一致したのでほぼ完成だと思います。ありがとうございます!
(暗号化はちょちょいっとずらすだけかと思っていたのですが、これだけの処理が必要なのですね…)
コード:
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <algorithm>
#include <random>
#include <typeinfo>
using namespace std;
// constants
const string ENCRYPTION_SUFFIX("(encrypted)");
const string DECRYPTION_SUFFIX("(decrypted)");
const string NL_ESC("\\n");
const string CR_ESC("\\r");
const string EOF_ESC("\\e");
const string ESC_ESC("\\\\");
// global variables
static ifstream filein;
static ofstream fileout;
static string fileInPath, fileOutPath;
static mt19937 randmt(0xffff);
static uniform_int_distribution<> dist(1, 255);
// bufをposから遡って\が偶数個なら素の文字、奇数個ならエスケープした文字
bool IsEscaped(const string& buf, const size_t pos)
{
// \*を見つけた時点ですでに後ろに一つ\があるが、while終了後--する手間を省くため0から始める
int count = 0;
while (buf[pos - ++count] == '\\');
return count & 1;
}
void ReplaceAll(string& buf, const string& target, const string& result)
{
size_t pos = 0;
size_t size = result.size();
while ((pos = buf.find(target, pos)) != string::npos){
buf.replace(pos, target.size(), result);
pos += size;
}
}
void ReplaceEscaped(string& buf, const string& target, const string& result)
{
size_t pos = 0;
size_t size = result.size();
while ((pos = buf.find(target, pos)) != string::npos){
if (IsEscaped(buf, pos)){
buf.replace(pos, target.size(), result);
}
pos += size;
}
}
void Encryption()
{
// 入力元oepn
filein.open(fileInPath.c_str());
// 出力先open
fileOutPath = fileInPath;
fileOutPath.insert(fileOutPath.rfind("."), ENCRYPTION_SUFFIX);
fileout.open(fileOutPath.c_str());
// 暗号化
string buf;
while (getline(filein, buf)){
buf += "\n";
// 暗号化
for (auto&& elem : buf){
elem += dist(randmt);
}
// \とNLとCR、EOFはエスケープして書き込む
ReplaceAll(buf, "\\", ESC_ESC);
ReplaceAll(buf, "\n", NL_ESC);
ReplaceAll(buf, "\r", CR_ESC);
ReplaceAll(buf, "\x1a", EOF_ESC);
fileout << buf;
}
}
void Decryption()
{
// 入力元oepn
filein.open(fileInPath.c_str());
// 出力先open
fileOutPath = fileInPath;
fileOutPath.insert(fileOutPath.rfind("."), DECRYPTION_SUFFIX);
fileout.open(fileOutPath.c_str());
// 暗号化
string buf;
while (getline(filein, buf)){
// NLとCR、EOFを戻す
ReplaceEscaped(buf, NL_ESC, "\n");
ReplaceEscaped(buf, CR_ESC, "\r");
ReplaceEscaped(buf, EOF_ESC, "\x1a");
// \\は\に
ReplaceAll(buf, ESC_ESC, "\\");
// 復号化
for (auto&& elem : buf){
elem -= dist(randmt);
}
fileout << buf;
}
}
int main()
{
cout.setf(ios_base::hex, ios_base::basefield);
cout.setf(ios_base::showbase);
filein.exceptions(ifstream::badbit);
fileout.exceptions(ofstream::badbit);
void(*Management[])() = {Encryption, Decryption};
while (true){
// パス取得(stdin)
cout << "type the path of the file you want to encrypt (you can also Drag and Drop the file).\n"
"type \"0\" to quit this program.\n";
getline(cin, fileInPath);
// 0が入力されれば終了
if (fileInPath == "0")
break;
// ""をはずす
const auto endIt = remove(fileInPath.begin(), fileInPath.end(), '\"');
fileInPath.erase(endIt, fileInPath.end());
// ファイル名に(encrypted)が含まれていれば、復号化処理にする
const bool toBeDecrypted = fileInPath.find(ENCRYPTION_SUFFIX, fileInPath.find_last_of("\\/")) != string::npos;
try{
// 必要な方を呼び出し
Management[toBeDecrypted]();
}
catch (exception& e){
cerr << "[ " << typeid(e).name() << " ] exception was thrown because of [ " << e.what() << " ]\n" << endl;
return -1;
}
clog << (toBeDecrypted ? "Decryption" : "Encryption") << " is successfully completed.\n\n";
}
clog << "end program..." << endl;
return 0;
}
Re: テキストファイルの暗号化の処理で行き詰っています
Posted: 2014年4月19日(土) 23:39
by h2so5
このような文字コードレベルでの暗号化は、普通はデータをバイナリデータとして扱うことが多いのでここまで複雑にはなりません。
今回のプログラムは暗号化後のデータもテキストファイルとして扱うような仕様になっているため、これだけのエスケープが必要になります。
暗号化の問題ではなくて、字句解析の問題ですね。
Re: テキストファイルの暗号化の処理で行き詰っています
Posted: 2014年4月20日(日) 13:12
by elle
h2so5さん
そうだったのですか…。
私もバイナリ処理は試したのですが、なぜかその時はgetlineに固執していてどうしても最後にゴミ文字が出てしまうので諦めていました。
冷静に考えればbinaryでgetlineはまずかったですね。
バイナリで作りなおしてみました(更に、4Gを超えるテキストファイルにも対応?してみました)。
確かにこちらの方が作りやすいですね…。
コード:
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <algorithm>
#include <random>
#include <memory>
#include <typeinfo>
using namespace std;
typedef unsigned long long int ullong;
// constants
const string ENCRYPTION_SUFFIX("(encrypted)");
const string DECRYPTION_SUFFIX("(decrypted)");
const size_t ALLOCATE_LIMIT = 1 << 20; // 約1MB
// global variables
static ifstream filein;
static ofstream fileout;
static string fileInPath, fileOutPath;
static mt19937 randmt(0xffff);
static uniform_int_distribution<> dist(1, 255);
void Encryption()
{
// 入力元oepn
filein.open(fileInPath.c_str(), ios::in | ios::binary);
// 出力先open
fileOutPath = fileInPath;
fileOutPath.insert(fileOutPath.rfind("."), ENCRYPTION_SUFFIX);
fileout.open(fileOutPath.c_str(), ios::out | ios::binary);
// fileSize取得
filein.seekg(0, filein.end);
const ullong fileSize = filein.tellg();
filein.seekg(0, filein.beg);
// alloc
const size_t allocateSize = fileSize < ALLOCATE_LIMIT ? static_cast<size_t>(fileSize) : ALLOCATE_LIMIT;
shared_ptr<char> buf(new char[allocateSize]);
// ブロックずつ暗号化して書き込む
while (!filein.eof()){
filein.read(buf.get(), allocateSize);
const size_t length = static_cast<size_t>(filein.gcount());
for (size_t i = 0; i < length; ++i){
buf.get()[i] += dist(randmt);
}
fileout.write(buf.get(), length);
}
}
void Decryption()
{
// 入力元oepn
filein.open(fileInPath.c_str(), ios::in | ios::binary);
// 出力先open
fileOutPath = fileInPath;
fileOutPath.insert(fileOutPath.rfind("."), DECRYPTION_SUFFIX);
fileout.open(fileOutPath.c_str(), ios::out | ios::binary);
// fileSize取得
filein.seekg(0, filein.end);
const ullong fileSize = filein.tellg();
filein.seekg(0, filein.beg);
// alloc
const size_t allocateSize = fileSize < ALLOCATE_LIMIT ? static_cast<size_t>(fileSize) : ALLOCATE_LIMIT;
shared_ptr<char> buf(new char[allocateSize]);
// ブロックずつ復号化して書き込む
while (!filein.eof()){
filein.read(buf.get(), allocateSize);
const size_t length = static_cast<size_t>(filein.gcount());
for (size_t i = 0; i < length; ++i){
buf.get()[i] -= dist(randmt);
}
fileout.write(buf.get(), length);
}
}
int main()
{
cout.setf(ios_base::hex, ios_base::basefield);
cout.setf(ios_base::showbase);
filein.exceptions(ifstream::badbit);
fileout.exceptions(ofstream::badbit);
void(*Management[])() = {Encryption, Decryption};
while (true){
// パス取得(stdin)
cout << "type the path of the file you want to encrypt (you can also Drag and Drop the file).\n"
"type \"0\" to quit this program.\n";
getline(cin, fileInPath);
// 0が入力されれば終了
if (fileInPath == "0")
break;
// ""をはずす
const auto endIt = remove(fileInPath.begin(), fileInPath.end(), '\"');
fileInPath.erase(endIt, fileInPath.end());
// ファイル名に(encrypted)が含まれていれば、復号化処理にする
const bool toBeDecrypted = fileInPath.find(ENCRYPTION_SUFFIX, fileInPath.find_last_of("\\/")) != string::npos;
try{
// 必要な方を呼び出し
Management[toBeDecrypted]();
}
catch (exception& e){
cerr << "[ " << typeid(e).name() << " ] exception was thrown because of [ " << e.what() << " ]\n" << endl;
return -1;
}
clog << (toBeDecrypted ? "Decryption" : "Encryption") << " is successfully completed.\n\n";
}
clog << "end program..." << endl;
return 0;
}
Re: テキストファイルの暗号化の処理で行き詰っています
Posted: 2014年4月20日(日) 13:33
by h2so5
shared_ptrに配列を入れるときは、deleterを明示的に指定しないといけません。
何も指定しないと解放時にdelete[]ではなくdeleteを利用してしまいますから。
コード:
shared_ptr<char> buf(new char[allocateSize], default_delete<char[]>());
Re: テキストファイルの暗号化の処理で行き詰っています
Posted: 2014年4月20日(日) 14:57
by elle
h2so5さん
あ、自動で判別されると思っていました…。
ということは上のプログラムはまるまる1MBメモリ解放し忘れていたことに…
危ないところでした、ありがとうございます。
修正版:
► スポイラーを表示
コード:
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <algorithm>
#include <random>
#include <memory>
#include <typeinfo>
using namespace std;
typedef unsigned long long int ullong;
// constants
const string ENCRYPTION_SUFFIX("(encrypted)");
const string DECRYPTION_SUFFIX("(decrypted)");
const size_t ALLOCATE_LIMIT = 1 << 30; // 約1MB
// global variables
static ifstream filein;
static ofstream fileout;
static string fileInPath, fileOutPath;
static mt19937 randmt(0xffff);
static uniform_int_distribution<> dist(1, 255);
void Encryption()
{
// 入力元oepn
filein.open(fileInPath.c_str(), ios::in | ios::binary);
// 出力先open
fileOutPath = fileInPath;
fileOutPath.insert(fileOutPath.rfind("."), ENCRYPTION_SUFFIX);
fileout.open(fileOutPath.c_str(), ios::out | ios::binary);
// fileSize取得
filein.seekg(0, filein.end);
const ullong fileSize = filein.tellg();
filein.seekg(0, filein.beg);
// alloc
const size_t allocateSize = min(static_cast<size_t>(fileSize), ALLOCATE_LIMIT);
shared_ptr<char> buf(new char[allocateSize], default_delete<char[]>());
// ブロックずつ暗号化して書き込む
while (!filein.eof()){
filein.read(buf.get(), allocateSize);
const size_t length = static_cast<size_t>(filein.gcount());
for (size_t i = 0; i < length; ++i){
buf.get()[i] += dist(randmt);
}
fileout.write(buf.get(), length);
}
}
void Decryption()
{
// 入力元oepn
filein.open(fileInPath.c_str(), ios::in | ios::binary);
// 出力先open
fileOutPath = fileInPath;
fileOutPath.insert(fileOutPath.rfind("."), DECRYPTION_SUFFIX);
fileout.open(fileOutPath.c_str(), ios::out | ios::binary);
// fileSize取得
filein.seekg(0, filein.end);
const ullong fileSize = filein.tellg();
filein.seekg(0, filein.beg);
// alloc
const size_t allocateSize = min(static_cast<size_t>(fileSize), ALLOCATE_LIMIT);
shared_ptr<char> buf(new char[allocateSize], default_delete<char[]>());
// ブロックずつ暗号化して書き込む
while (!filein.eof()){
filein.read(buf.get(), allocateSize);
const size_t length = static_cast<size_t>(filein.gcount());
for (size_t i = 0; i < length; ++i){
buf.get()[i] -= dist(randmt);
}
fileout.write(buf.get(), length);
}
}
int main()
{
cout.setf(ios_base::hex, ios_base::basefield);
cout.setf(ios_base::showbase);
filein.exceptions(ifstream::badbit);
fileout.exceptions(ofstream::badbit);
void(*Management[])() = {Encryption, Decryption};
while (true){
// パス取得(stdin)
cout << "type the path of the file you want to encrypt (you can also Drag and Drop the file).\n"
"type \"0\" to quit this program.\n";
getline(cin, fileInPath);
// 0が入力されれば終了
if (fileInPath == "0")
break;
// ""をはずす
const auto endIt = remove(fileInPath.begin(), fileInPath.end(), '\"');
fileInPath.erase(endIt, fileInPath.end());
// ファイル名に(encrypted)が含まれていれば、復号化処理にする
const bool toBeDecrypted = fileInPath.find(ENCRYPTION_SUFFIX, fileInPath.find_last_of("\\/")) != string::npos;
try{
// 必要な方を呼び出し
Management[toBeDecrypted]();
}
catch (exception& e){
cerr << "[ " << typeid(e).name() << " ] exception was thrown because of [ " << e.what() << " ]\n" << endl;
return -1;
}
clog << (toBeDecrypted ? "Decryption" : "Encryption") << " is successfully completed.\n\n";
}
clog << "end program..." << endl;
return 0;
}
Re: テキストファイルの暗号化の処理で行き詰っています
Posted: 2014年4月20日(日) 18:54
by elle
時間計測したら結構遅かったので高速化(というより遅すぎたのを改善)してみました。
上のコードでは3万行くらいのテキストの暗号化・復号化に2139ms程かかっていましたが、
1バイトずつ暗号化してたのを4バイトずつにすることにより540msほどになり、
mt19937をuniform_int_distriburionを取り除いて単に呼び出したら131msほどになりました。
更に、mt19937_64を使用することで88msほどになりました。
EncryptionもDecryptionもほぼ同じ処理なので、統合して内部で条件分岐したところ、
パフォーマンスの低下するかと思いきや、なぜかこちらの方が早いケースもあり、誤差の範囲に思えます。
(どちらも72ms~98msほど)
数万回通ってるはずなのに…最適化されているのでしょうか。
ご参考までに。
► スポイラーを表示
コード:
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <algorithm>
#include <random>
#include <memory>
#include <chrono>
#include <typeinfo>
#include <cstdint>
using namespace std;
using namespace std::chrono;
typedef unsigned long long int ullong;
// constants
const string ENCRYPTION_SUFFIX("(encrypted)");
const string DECRYPTION_SUFFIX("(decrypted)");
const size_t ALLOCATE_LIMIT = 1 << 30; // 約1GB
// global variables
static ifstream filein;
static ofstream fileout;
static string fileInPath, fileOutPath;
static mt19937 randmt(0xffff);
static mt19937_64 randmt64(0xffff);
void Encryption()
{
// 入力元oepn
filein.open(fileInPath.c_str(), ios::in | ios::binary);
// 出力先open
fileOutPath = fileInPath;
fileOutPath.insert(fileOutPath.rfind("."), ENCRYPTION_SUFFIX);
fileout.open(fileOutPath.c_str(), ios::out | ios::binary);
// fileSize取得
filein.seekg(0, filein.end);
const ullong fileSize = filein.tellg();
filein.seekg(0, filein.beg);
// alloc
size_t allocateSize = fileSize < ALLOCATE_LIMIT ? static_cast<size_t>(fileSize) : ALLOCATE_LIMIT;
allocateSize += 8 - allocateSize % 8;
shared_ptr<char> buf(new char[allocateSize], default_delete<char[]>());
// 計測開始
const system_clock::time_point t = system_clock::now();
// ブロックずつ暗号化して書き込む
while (!filein.eof()){
filein.read(buf.get(), allocateSize);
const size_t length = static_cast<size_t>(filein.gcount());
for (size_t i = 0; i < length / 8; ++i){
reinterpret_cast<__int64*>(buf.get())[i] += randmt64();
}
fileout.write(buf.get(), length);
}
// 計測終了
const milliseconds elapsed = duration_cast<milliseconds>(system_clock::now() - t);
clog << elapsed.count() << " miliseconds elapsed while encrypting.\n";
}
void Decryption()
{
// 入力元oepn
filein.open(fileInPath.c_str(), ios::in | ios::binary);
// 出力先open
fileOutPath = fileInPath;
fileOutPath.insert(fileOutPath.rfind("."), DECRYPTION_SUFFIX);
fileout.open(fileOutPath.c_str(), ios::out | ios::binary);
// fileSize取得
filein.seekg(0, filein.end);
const ullong fileSize = filein.tellg();
filein.seekg(0, filein.beg);
// alloc
size_t allocateSize = fileSize < ALLOCATE_LIMIT ? static_cast<size_t>(fileSize) : ALLOCATE_LIMIT;
allocateSize += 8 - allocateSize % 8;
shared_ptr<char> buf(new char[allocateSize], default_delete<char[]>());
// 計測開始
const system_clock::time_point t = system_clock::now();
// ブロックずつ暗号化して書き込む
while (!filein.eof()){
filein.read(buf.get(), allocateSize);
const size_t length = static_cast<size_t>(filein.gcount());
for (size_t i = 0; i < length / 8; ++i){
reinterpret_cast<__int64*>(buf.get())[i] -= randmt64();
}
fileout.write(buf.get(), length);
}
// 計測終了
const milliseconds elapsed = duration_cast<milliseconds>(system_clock::now() - t);
clog << elapsed.count() << " miliseconds elapsed while decrypting.\n";
}
void Dealing(const bool toBeDecrypted)
{
// 入力元oepn
filein.open(fileInPath.c_str(), ios::in | ios::binary);
// 出力先open
fileOutPath = fileInPath;
fileOutPath.insert(fileOutPath.rfind("."), toBeDecrypted ? DECRYPTION_SUFFIX : ENCRYPTION_SUFFIX);
fileout.open(fileOutPath.c_str(), ios::out | ios::binary);
// fileSize取得
filein.seekg(0, filein.end);
const ullong fileSize = filein.tellg();
filein.seekg(0, filein.beg);
// alloc
size_t allocateSize = fileSize < ALLOCATE_LIMIT ? static_cast<size_t>(fileSize) : ALLOCATE_LIMIT;
allocateSize += 8 - allocateSize % 8;
shared_ptr<char> buf(new char[allocateSize], default_delete<char[]>());
// 計測開始
const system_clock::time_point t = system_clock::now();
// ブロックずつ暗号化して書き込む
while (!filein.eof()){
filein.read(buf.get(), allocateSize);
const size_t length = static_cast<size_t>(filein.gcount());
for (size_t i = 0; i < length / 8; ++i){
reinterpret_cast<__int64*>(buf.get())[i] += toBeDecrypted ? randmt64() : randmt64() * -1;
}
fileout.write(buf.get(), length);
}
// 計測終了
const milliseconds elapsed = duration_cast<milliseconds>(system_clock::now() - t);
clog << elapsed.count() << " miliseconds elapsed while " << (toBeDecrypted ? "decrypting" : "encrypting") << " .\n";
}
int main()
{
cout.setf(ios_base::hex, ios_base::basefield);
cout.setf(ios_base::showbase);
filein.exceptions(ifstream::badbit);
fileout.exceptions(ofstream::badbit);
void(*Management[])() = {Encryption, Decryption};
while (true){
// パス取得(stdin)
cout << "type the path of the file you want to encrypt (you can also Drag and Drop the file).\n"
"type \"0\" to quit this program.\n";
getline(cin, fileInPath);
// 0が入力されれば終了
if (fileInPath == "0")
break;
// ""をはずす
const auto endIt = remove(fileInPath.begin(), fileInPath.end(), '\"');
fileInPath.erase(endIt, fileInPath.end());
// ファイル名に(encrypted)が含まれていれば、復号化処理にする
const bool toBeDecrypted = fileInPath.find(ENCRYPTION_SUFFIX, fileInPath.find_last_of("\\/")) != string::npos;
try{
// 必要な方を呼び出し
// Dealing(toBeDecrypted); // 内部で条件分岐
Management[toBeDecrypted](); // 関数ポインタ配列からの呼び出し
}
catch (exception& e){
cerr << "[ " << typeid(e).name() << " ] exception was thrown because of [ " << e.what() << " ]\n" << endl;
return -1;
}
clog << (toBeDecrypted ? "Decryption" : "Encryption") << " is successfully completed.\n\n";
}
clog << "end program..." << endl;
return 0;
}
Re: テキストファイルの暗号化の処理で行き詰っています
Posted: 2014年4月20日(日) 19:08
by h2so5
elle さんが書きました:
EncryptionもDecryptionもほぼ同じ処理なので、統合して内部で条件分岐したところ、
パフォーマンスの低下するかと思いきや、なぜかこちらの方が早いケースもあり、誤差の範囲に思えます。
(どちらも72ms~98msほど)
数万回通ってるはずなのに…最適化されているのでしょうか。
分岐するといっても符号が違うだけでその後の処理に影響がないですよね。
しかも関数の実行中は必ず同じ方に分岐するので、分岐予測の失敗もないですし。
パフォーマンスに差がないのは不思議なことではないと思います。
Re: テキストファイルの暗号化の処理で行き詰っています
Posted: 2014年4月20日(日) 20:22
by elle
h2so5さん
なるほど…確かにそうですね…。
逆アセンブルを確認してみると、純粋にje...jmpが1セット増えているだけでした。
jeが数万回増えるくらいでは動作に大きな影響はないということでしょうか。
if文は少ない方がいいと聞いたことがあったのですが、if文の負荷にもいろいろあるのですね。
Re: テキストファイルの暗号化の処理で行き詰っています
Posted: 2014年4月20日(日) 21:15
by h2so5
elle さんが書きました:
jeが数万回増えるくらいでは動作に大きな影響はないということでしょうか。
if文は少ない方がいいと聞いたことがあったのですが、if文の負荷にもいろいろあるのですね。
私もそんなに詳しくはないですが、if文を少なく、というのはパイプラインハザードやキャッシュミスの発生率を下げるのが目的なんじゃないかと思います。
今回の場合は、条件分岐を入れてもそのような問題が起きるコードではないはずです。
Re: テキストファイルの暗号化の処理で行き詰っています
Posted: 2014年4月21日(月) 20:46
by elle
h2so5さん
そういうことでしたか…if文=重いもの、と思い込んでいました。
ということはやはりif文も工夫して使えばパフォーマンスに必ずしも悪影響ではないということですね。
関数の統合に関して今日改めて試行したところ、
暗号化の方が速度に差がない点は同じでしたが、復号化の方は * -1してる分10ms程遅くなっていました(なぜ気づかなかったのか…)。
ビット演算に変えたらほぼ同じ速度になりました。
やはりかかる時間の大部分は乱数の生成のようなので、XORShiftに変えたところさらに10msほど速くなりました(67ms)。
更に、リリースビルドにしたところ30ms(!)になりました。こんなに違うとは…。
このあたりが限界…でしょうかね。
► スポイラーを表示
コード:
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <algorithm>
#include <random>
#include <memory>
#include <chrono>
#include <typeinfo>
#include <cstdint>
using namespace std;
using namespace std::chrono;
typedef unsigned long long int ullong;
// constants
const string ENCRYPTION_SUFFIX("(encrypted)");
const string DECRYPTION_SUFFIX("(decrypted)");
const size_t ALLOCATE_LIMIT = 1 << 27; // 128MB
// global variables
static ifstream filein;
static ofstream fileout;
static string fileInPath, fileOutPath;
class Xorshift64 {
public:
Xorshift64()
:mS0(2685821657736338717LL), mS1(1181783497276652981LL)
{
}
Xorshift64(uint64_t s1, uint64_t s2)
:mS0(s1), mS1(s2)
{
}
~Xorshift64()
{
}
uint64_t Next()
{
uint64_t s1 = mS0;
const uint64_t s0 = mS1;
mS0 = s0;
s1 ^= s1 << 23;
return (mS1 = (s1 ^ s0 ^ (s1 >> 17) ^ (s0 >> 26))) + s0;
}
private:
uint64_t mS0, mS1;
};
bool Dealing(const bool toBeDecrypted)
{
// 入力元oepn
filein.open(fileInPath.c_str(), ios::in | ios::binary);
if (!filein){
cerr << "failed to open the file you requested.\n";
return false;
}
// 出力先open
fileOutPath = fileInPath;
fileOutPath.insert(fileOutPath.rfind("."), toBeDecrypted ? DECRYPTION_SUFFIX : ENCRYPTION_SUFFIX);
fileout.open(fileOutPath.c_str(), ios::out | ios::binary);
// fileSize取得
filein.seekg(0, filein.end);
const ullong fileSize = filein.tellg();
filein.seekg(0, filein.beg);
// alloc
size_t allocateSize = fileSize < ALLOCATE_LIMIT ? static_cast<size_t>(fileSize) : ALLOCATE_LIMIT;
allocateSize += sizeof(int64_t) - allocateSize % sizeof(int64_t); // ヒープが8の倍数になるように
shared_ptr<char> buf(new char[allocateSize], default_delete<char[]>());
// 計測開始
const system_clock::time_point t = system_clock::now();
Xorshift64 randxor;
// ブロックずつ暗号化して書き込む
while (!filein.eof()){
filein.read(buf.get(), allocateSize);
const size_t length = static_cast<size_t>(filein.gcount());
for (size_t i = 0; i < length / sizeof(int64_t); ++i){
reinterpret_cast<int64_t*>(buf.get())[i] += toBeDecrypted ? randxor.Next() : (randxor.Next() ^ 0xffffffffffffffffLL) + 1;
}
fileout.write(buf.get(), length);
}
// 計測終了
const milliseconds elapsed = duration_cast<milliseconds>(system_clock::now() - t);
clog << elapsed.count() << " miliseconds elapsed while decrypting.\n";
return true;
}
int main()
{
cout.setf(ios_base::hex, ios_base::basefield);
cout.setf(ios_base::showbase);
filein.exceptions(ifstream::badbit);
fileout.exceptions(ofstream::badbit);
while (true){
// パス取得(stdin)
cout << "type the path of the file you want to encrypt (you can also Drag and Drop the file).\n"
"type \"0\" to quit this program.\n";
getline(cin, fileInPath);
// 0が入力されれば終了
if (fileInPath == "0")
break;
// ""をはずす
const auto endIt = remove(fileInPath.begin(), fileInPath.end(), '\"');
fileInPath.erase(endIt, fileInPath.end());
// ファイル名に(encrypted)が含まれていれば、復号化処理にする
const bool toBeDecrypted = fileInPath.find(ENCRYPTION_SUFFIX, fileInPath.find_last_of("\\/")) != string::npos;
try{
if (!Dealing(toBeDecrypted))
continue;
}
catch (exception& e){
cerr << "[ " << typeid(e).name() << " ] exception was thrown because of [ " << e.what() << " ]\n" << endl;
return -1;
}
clog << (toBeDecrypted ? "Decryption" : "Encryption") << " is successfully completed.\n\n";
}
clog << "end program..." << endl;
return 0;
}
Re: テキストファイルの暗号化の処理で行き詰っています
Posted: 2014年4月21日(月) 21:17
by h2so5
ちなみに、リリースビルドすると * -1 の部分も最適化されるのでビット演算にする意味はないです。
Re: テキストファイルの暗号化の処理で行き詰っています
Posted: 2014年4月21日(月) 21:43
by elle
h2so5さん
あ…本当ですか…_| ̄|○
知りませんでした…。