🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
バイナリ

バイナリは、「0」と「1」だけで表現されている2進数のデータ形式。または、テキスト以外の情報でデータが記述されているファイルを指します。コンピューター内の処理は全て2進数で表記されています。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

ファイルI/O

ファイルI/Oは、コンピューターにおけるファイルの入出力です。これは生成/削除やファイルを読み込んだり、出力をファイルに書き込むようなディレクトリやファイルの運用を含みます。

Q&A

解決済

1回答

3818閲覧

バイト列をBinaryWriterで出力してもテキストで出力される

tomy-c

総合スコア179

バイナリ

バイナリは、「0」と「1」だけで表現されている2進数のデータ形式。または、テキスト以外の情報でデータが記述されているファイルを指します。コンピューター内の処理は全て2進数で表記されています。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

ファイルI/O

ファイルI/Oは、コンピューターにおけるファイルの入出力です。これは生成/削除やファイルを読み込んだり、出力をファイルに書き込むようなディレクトリやファイルの運用を含みます。

0グッド

1クリップ

投稿2020/12/14 01:01

編集2020/12/14 05:23

現在、数年来のリハビリがてら、
C#のコンソールプログラムでRSAを用いた暗号化プログラムを作っているのですが、公開鍵、秘密鍵を生成し、バイナリファイルで出力しようとしています。
成果物としてはRSACryptoServiceProvider.ToXmlStringで出力したstringをテキストエディタで普通に開いただけでは内容が理解できないバイナリファイルにすることをイメージしています。

暗号化、復号化に関しては正しく動作するプログラムが完成しているのですが、
肝心の公開鍵、秘密鍵をC#のBinaryWriterで出力しても、出力したファイルは普通のテキスト形式で、メモ帳で開いても普通に中身が見れてしまいます。
そのため、別ツールなどでBinaryReader等を用い読み込んでもフォーマットの問題でエラーが発生してしまいます。
デバッグなどで一時停止し、書き込む中身のバイト配列変数等を確認しても変なデータ等は見られず、似たような事例も探しても見当たらないため、原因がわかりません。
どなたかご存じないでしょうか?

ソースコード

色々調査のためにいじってたので汚いです。

C#

1 /// <summary> 2 /// 公開鍵、秘密鍵のペアを作成してファイル出力する 3 /// </summary> 4 /// <param name="binary_option_flg">バイナリ形式で出力するか。</param> 5 /// <returns>作成した鍵のファイルを格納したフォルダパス。失敗時はNull</returns> 6 public static string PutRSAKey(bool binary_option_flg = false) 7 { 8 //Assembly myAssembly = Assembly.GetEntryAssembly(); 9 //string path = myAssembly.Location; 10 11 string putdir = Directory.GetCurrentDirectory() + "/Keypair_" + DateTime.Now.ToString("yyyyMMddHHmmss") + "/"; 12 string pub_file_path = putdir + "public.dat"; 13 string pri_file_path = putdir + "private.dat"; 14 15 try 16 { 17 string public_key; 18 string private_key; 19 using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider()) 20 { 21 public_key = rsa.ToXmlString(false); //falseで公開鍵だけ返却 22 private_key = rsa.ToXmlString(true); //trueで公開、秘密鍵両方を返却 23 } 24 25 //出力フォルダ作成 26 if (!Directory.Exists(putdir)) 27 { 28 Directory.CreateDirectory(putdir); 29 } 30 31 //using (var fs_pub = new FileStream(pub_file_path, FileMode.Create)) 32 //using (var fs_pri = new FileStream(pri_file_path, FileMode.Create)) 33 34 if (binary_option_flg) 35 { 36 using (var writer = new BinaryWriter(new FileStream(pub_file_path, FileMode.Create))) 37 { 38 //byte[] p = Encoding.GetEncoding("utf-8").GetBytes(public_key); 39 byte[] p = Encoding.GetEncoding("utf-8").GetBytes("ABC あいう"); 40 //for (int i=0; i< p.GetLength(0); i++) { 41 // writer.Write(p[i]); 42 //} 43 Console.WriteLine(p[0].ToString()); //正しくバイト型に変換できている 44 writer.Write(p,0,p.Length); //バイナリ形式で出力(※テキストで出力される) 45 } 46 using (var writer = new BinaryWriter(new FileStream(pri_file_path, FileMode.Create))) 47 { 48 writer.Write(private_key); 49 } 50 51 // byte[] pub = Encoding.GetEncoding("utf-8").GetBytes(public_key); 52 // byte[] pri = Encoding.GetEncoding("utf-8").GetBytes(private_key); 53 54 // //バイナリ形式で保存 55 // using (var sw = new BinaryWriter(fs_pub)) 56 //{ 57 // sw.Write(pub); 58 //} 59 //using (var sw = new BinaryWriter(fs_pri)) 60 //{ 61 // sw.Write(pri); 62 //} 63 } 64 else 65 { 66 ////テキスト形式、上書き、UTF-8 67 //using (var sw = new StreamWriter(fs_pub, Encoding.UTF8)) 68 //{ 69 // sw.Write(public_key); 70 //} 71 //using (var sw = new StreamWriter(fs_pri, Encoding.UTF8)) 72 //{ 73 // sw.Write(private_key); 74 //} 75 } 76 77 return putdir; 78 } 79 catch 80 { 81 return null; 82 } 83 }

###指摘後修正(ベストアンサー後)
※今回の問題はそもそも自身のイメージしているバイナリファイルの概念が間違っているのが原因でした。
そのため、異常して上げた箇所の動作はそもそもが正常な動作であり、それを間違った解釈から異常と判断していたのが問題でした。

C#

1 /// <summary> 2 /// 公開鍵、秘密鍵のペアを作成してファイル出力する 3 /// </summary> 4 /// <returns>作成した鍵のファイルを格納したフォルダパス。失敗時はNull</returns> 5 public static string PutRSAKey() 6 { 7 8 string putdir = Directory.GetCurrentDirectory() + "/Keypair_" + DateTime.Now.ToString("yyyyMMddHHmmss") + "/"; 9 string pub_file_path = putdir + "public.dat"; 10 string pri_file_path = putdir + "private.dat"; 11 12 try 13 { 14 string public_key; 15 string private_key; 16 using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider()) 17 { 18 public_key = rsa.ToXmlString(false); //falseで公開鍵だけ返却 19 private_key = rsa.ToXmlString(true); //trueで公開、秘密鍵両方を返却 20 } 21 22 //出力フォルダ作成 23 if (!Directory.Exists(putdir)) 24 { 25 Directory.CreateDirectory(putdir); 26 } 27 28 //テキスト形式、上書き、UTF-8 29 using (var sw = new StreamWriter(pub_file_path)) 30 { 31 sw.Write(Base64Encode(public_key)); 32 } 33 using (var sw = new StreamWriter(pri_file_path)) 34 { 35 sw.Write(Base64Encode(private_key)); 36 } 37 38 39 return putdir; 40 } 41 catch 42 { 43 return null; 44 } 45 } 46 47 /// <summary> 48 /// Base64で文字列を難読化する 49 /// </summary> 50 /// <param name="str"></param> 51 /// <returns></returns> 52 /// <remarks>エンコードはutf-8固定</remarks> 53 private static string Base64Encode(string str) 54 { 55 Encoding enc = Encoding.GetEncoding("UTF-8"); 56 return Convert.ToBase64String(enc.GetBytes(str)); 57 } 58 59 /// <summary> 60 /// Base64で難読化された文字列を復号化する 61 /// </summary> 62 /// <param name="str"></param> 63 /// <returns></returns> 64 /// <remarks>エンコードはutf-8固定</remarks> 65 private static string Base64Decode(string str) 66 { 67 Encoding enc = Encoding.GetEncoding("UTF-8"); 68 return enc.GetString(Convert.FromBase64String(str)); 69 } 70

試したこと

・バイト配列への変換方法を一文字づつに変えた → 変わらず
・適当な文字列そのものをバイト配列に変換して出力してみた → やっぱりテキストで出力される
・BinaryWriterの引数に普通の型(string)での出力をMSDNで見つけたので試した →テキスト出力される

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zuishin

2020/12/14 01:07

BinaryWriter が何をするものかを調べてください。
退会済みユーザー

退会済みユーザー

2020/12/14 01:12 編集

コードのどの行のことを言っているのですか? コメント「//正しくバイト型に変換できている」の下のこれですか? ⇒ writer.Write(p,0,p.Length);
tomy-c

2020/12/14 01:22 編集

SurferOnWwwさん、申し訳ありません、問題発生箇所は writer.Write(p,0,p.Length); の出力部分になります。
kikukiku

2020/12/14 01:23

public_key = rsa.ToXmlString(false);でセットされたpublic_keyは、 テキスト情報なので勘違いしていませんか?
退会済みユーザー

退会済みユーザー

2020/12/14 01:30

入力元データと、実際に出力したい(想定している)データを記載した方がよいかもしれません。現状、stringをバイト配列にして書き込んでいるだけなので、テキストが出力されるのは当たり前です。
退会済みユーザー

退会済みユーザー

2020/12/14 01:35

文字列 "ABC あいう" の utf-8 のバイト列をファイルに書き込んだからメモ帳でそのファイルを開くとその文字列が表示されるという当たり前の話のように思えますが?
tomy-c

2020/12/14 01:52 編集

皆さんのご指摘からおそらく自分のファイル関連に関しての基礎知識が色々間違っていると確信し始めていますが(このあたりのコードを組むのが初めて)、鍵情報が含まれた文字列をバイナリデータ(2進数のデータ)に変換してBinaryWriterで出力することでバイナリファイル(ヘキサエディタを使わないと読めないようなファイル)を目的として作っています。
退会済みユーザー

退会済みユーザー

2020/12/14 01:53 編集

> 成果物としてはRSACryptoServiceProvider.ToXmlStringで出力したstringをテキストエディタで普通に開いただけでは内容が理解できないバイナリファイルにすることをイメージしています。 あなたの言う「バイナリファイル」というのは一体何なのですか? 「出力したstring」というのは開けば読める文字列らしいので、それを暗号化してファイルに保存しない限りはファイルを開いて読めるのは当たり前ですけど、そのあたり理解できてますか? 暗号化まではしなくても BASE64 にエンコードして保存してはいかが? それでも読む人が読めば読めますけど、知らない人には理解不能ですから。
Zuishin

2020/12/14 01:59

BinaryWriter が何をするものか調べましたか?
Zuishin

2020/12/14 02:03

> 自戒の為に書く問題解決の心得 この中に「信頼できる情報ソースにあたる」がありません。根本的に間違っています。
退会済みユーザー

退会済みユーザー

2020/12/14 02:17

> 鍵情報が含まれた文字列をバイナリデータ(2進数のデータ)に変換してBinaryWriterで出力することでバイナリファイル(ヘキサエディタを使わないと読めないようなファイル)を目的として作っています。 まず、そのバイナリ形式をどうするかから考える所から始めてください。例えば、テキストをzipファイルに圧縮すれば、一応テキストエディタでは読めないバイナリが出来上がります。(圧縮解凍ソフトでは当然読めますが) インプットとアウトプットを明確にしないと、誰も回答する事は出来ません。
tomy-c

2020/12/14 02:19

<Zuishinさん MSDNでは ''' プリミティブ型をバイナリでストリームに書き込みます。特定のエンコーディングの文字列の書き込みをサポートします。 注釈: プリミティブデータ型のストリームへの書き込みを容易にするメソッドが用意されています。 たとえば、メソッドを使用し Write て、1バイト値としてストリームにブール値を書き込むことができます。 ''' とあり、バイナリでストリームに書き込みます。とあったのでこちらを使えばバイナリで書き込まれると認識していました。 (いろいろ調べても普通のテキスト形式で書き込むStreamWriterとバイナリ形式で書き込むBinaryWriterという形でヒットしました。)
tomy-c

2020/12/14 02:24

<SurferOnWwwさん < あなたの言う「バイナリファイル」というのは一体何なのですか?  という箇所についてですが、自分の中(独学なので間違っている気がしますが)ではバイナリ(2進数)のデータを出力した[人には理解しづらい]ファイル という認識でいました。 そのため、文字列をバイト配列に変換して出力すればそれはバイナリファイルなのではという考えでこのプログラムを作っています。
退会済みユーザー

退会済みユーザー

2020/12/14 02:25

何かすごい勘違いをしていそうですが、貴方の言うテキストというものも、ファイルに書き込まれた状態では、テキストと解釈する事が出来る形式の只のバイナリなのです。
退会済みユーザー

退会済みユーザー

2020/12/14 02:39

> 自分の中(独学なので間違っている気がしますが)ではバイナリ(2進数)のデータを出力した[人には理解しづらい]ファイル という認識でいました。 先のコメントでも書きましたが、文字列 "ABC あいう" の utf-8 のバイト列をファイルに書き込んだからメモ帳でそのファイルを開くとその文字列が表示されるという当たり前の話ということを理解してください。そこに理解がないとこの先話は通じません。 これも先のコメントに書きましたが、「出力したstring」というのは開けば読める文字列らしいので、それを暗号化してファイルに保存しない限りはファイルを開いて読めるのは当たり前です。エンコーディングによってバイト列の内容は異なりますが、読めることには変わりありません。 暗号化まではしなくても BASE64 にエンコードして保存してはいかが? それでも読む人が読めば読めますけど、知らない人には理解不能ですから。
退会済みユーザー

退会済みユーザー

2020/12/14 03:03

BASE64 にエンコードして保存する案を回答欄に書いておきます。BASE64 では読む人が読めば読めるのでダメと言うことであれば、BASE64 に代えて暗号化を考えるということになると思います。
tomy-c

2020/12/14 03:05

<radianさん、SurferOnWwwさん <何かすごい勘違いをしていそうですが、貴方の言うテキストというものも、ファイルに書き込まれた状態では、テキストと解釈する事が出来る形式の只のバイナリなのです。 <先のコメントでも書きましたが、文字列 "ABC あいう" の utf-8 のバイト列をファイルに書き込んだからメモ帳でそのファイルを開くとその文字列が表示されるという当たり前の話ということを理解してください。 あぁ、なるほど。メモ帳などのテキストエディタは[文字のバイナリ]を文字列にデコードすることで人が理解できる文字として表示するから、今回平文の文字列を何も加工せずにバイナリとして出力したら当然メモ帳で開いたときにテキストとして表示されるということですね。 その辺の知識が欠落していたため、今回の動作は正常なのに異常と自身が認識したんだと思います・・・
kikukiku

2020/12/14 03:12

「暗号化、復号化に関しては正しく動作するプログラムが完成しているのですが」と記述されているので 暗号化キーを記録したファイルを読みだしてなんかするアプリはすでに出来ていると解釈しました。 だとすると、そのアプリのファイル仕様が明確になっているはずです。 その仕様を確認しましょう。 その仕様とは、暗号化キーをファイル出力と言っても、 形式をどのようなものにするかによっても変わってきますので、 もっと深く仕様を確認する必要があります。 その仕様が出てくると、具体的にこんなコードで出力できるという回答をすることができます。
guest

回答1

0

ベストアンサー

何故ダメなのかは質問のコメント欄に多々書かれているので省略し、BASE64 にエンコードして保存する案を以下に書いておきます。

成果物としてはRSACryptoServiceProvider.ToXmlStringで出力したstringをテキストエディタで普通に開いただけでは内容が理解できないバイナリファイルにすることをイメージしています。

「出力したstring」というのは開けば読める文字列らしいので、それを暗号化してファイルに保存しない限りはファイルを開いて読めるのは当たり前の話ということを理解してください。エンコーディングによってバイト列の内容は異なりますが、読めることには変わりありません。

暗号化まではしなくても、以下のように BASE64 にエンコードして保存してはいかが? それでも読む人が読めば読めますけど、知らない人には理解不能です。

BASE64 では読む人が読めば読めるのでダメと言うことであれば、BASE64 に代えて暗号化を考えるということになると思います。

using System; using System.Linq; using System.Text; using System.IO; using System.IO.Compression; using System.Xml.Linq; namespace ConsoleApp2 { class Program { static void Main(string[] args) { string pub_file_path = @"C:\Users\surfe\Documents\Visual Studio 2019\CsProject\ConsoleApp2\ConsoleApp2\public.dat"; using (var writer = new StreamWriter(pub_file_path)) { byte[] p = Encoding.GetEncoding("utf-8").GetBytes("ABC あいう"); string base64 = Convert.ToBase64String(p); Console.WriteLine(base64); writer.Write(base64); } using (var reader = new StreamReader(pub_file_path)) { string base64 = reader.ReadToEnd(); Console.WriteLine(base64); byte[] b = Convert.FromBase64String(base64); string original = Encoding.GetEncoding("utf-8").GetString(Convert.FromBase64String(base64)); Console.WriteLine(original); } Console.WriteLine("\n------------------------\n"); // ・・・中略・・・ }

実行結果は:

イメージ説明

バイナリエディタで見ると:

イメージ説明

メモ帳で見ると:

イメージ説明

投稿2020/12/14 03:14

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tomy-c

2020/12/14 05:16

自身の基礎知識が間違って解釈していたために大事になってしまい申し訳ありません。 今回は自身しか使う予定の無い内製ツールだった為、大きな被害はありませんが、独学は、間違って解釈しているかどうかは実際に被害を出して他者に指摘していただくまで分からないというリスクを実感しました・・・ 一応ご指摘を元に修正したコードを本文に記載します。(下記の解決方法は自己解決のみと注記があるため)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問