暗号化について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
かかし

暗号化について

#1

投稿記事 by かかし » 15年前

暗号化に関して勉強しようと思い、先輩の書かれた下記のコードを参考にしているのですがよくわかりません。
わかる事は、「2バイト文字と1バイト文字を区別して暗号化するプログラム」「シフトJISの2バイトコードが関係している」という事くらいです。
 (知識が乏しく、質問の仕方も悪いとは思いますがよろしくお願いします。)

質問は
①while文の上の「i=0;」は何のためにあるか?
②while文の中の下記の部分の働きは何?
bun=c*256+c1+k;         →何故cに256を掛けるのか?
angou=bun/256;       →256で割る意味は?
angou[i+1]=bun%256; →何故bunを%256で割った余りを求めるのか?
i++;
i++; →何故i++が二つある?

③その下のelse内の「angou=c+(k%256);」は何を意味しているのか?
④「len=i;」は何故あるか?
⑤「angou[len]=0;」は何故あるか?


コード:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void){

FILE *fp,*ff;
int k,i,len,c,c1;
unsigned short int bun;
unsigned char fname[80];
char angou[10000];

printf("鍵の値入力:");
scanf("%d",&k);
getchar();
printf("鍵=%d\n",k);


    printf("ファイル名 : ");
    gets(fname);

    fp = fopen(fname, "r");
    if(fp == NULL){
        printf("ファイルが開きません\n");
        exit(1);
    }

	i=0;
	while ((c = fgetc(fp)) != EOF){		
         
		  if   (c >= 0x81 && c <= 0x9F)  {			

		  if ((c1 = fgetc(fp)) == EOF)break;
		 	   	
            bun=c*256+c1+k;				
			angou[i]=bun/256;
			angou[i+1]=bun%256;
			i++;
			i++;
		  }
		  else {
              angou[i]=c+(k%256);			
			  i++;
		  }
	}

	len=i;
	printf("%d\n",len);
	if ((ff = fopen("Filex.txt", "w")) == NULL) {  
                                                    
        printf ("Can't Open C Source File!\n" );
        exit (2);									
	}
	
	angou[len]=0;

	fwrite(angou,len,1,ff);							
	
	printf("%d\n",i);						
	fclose(fp);
	
	return (0);
    	
}
CODEタグを修正させていただきました。 by softya(ソフト屋)

アバター
bitter_fox
記事: 607
登録日時: 15年前
住所: 大阪府

Re: 暗号化について

#2

投稿記事 by bitter_fox » 15年前

かかし さんが書きました: ①while文の上の「i=0;」は何のためにあるか?
これは初期化に当たります。
配列へのアクセスに使用しているので0で初期化していますね。
かかし さんが書きました:②while文の中の下記の部分の働きは何?

コード:

			bun=c*256+c1+k;	        →何故cに256を掛けるのか?	
			angou[i]=bun/256;       →256で割る意味は?
			angou[i+1]=bun%256;            →何故bunを%256で割った余りを求めるのか?
			i++;
			i++;                                    →何故i++が二つある?
上を見てもらえれば分かる通り二つ連続して代入しています。
もし、iを一つしか進めていないと次の代入の際に一つが上書きされてしまいます。ですので、i++が二つあります。

上の三行ですがこれは暗号アルゴリズムの話になるので、先輩に確認した方が適切かと思います。
一応、見てわかる範囲で書いてみます・・・

bun = c*256+c1+kですが、
まず、二バイト文字の一バイト目(上位バイト)をcそして二バイト目(下位バイト)をc1としていて、
これを一つのつながった数値と見なしたいようです。
(つまり0x81,0x23と言った風になっていたとして、これを0x8123と言った風にしたいということですね。)
そうするためにはまず、0x81(c)に0x100(256)を掛けることで0x8100になります。
さらに、それに0x23(c1)を足すと0x8123になりますね。
それに暗号鍵を足しています。(次の説明のためにkを12として、その結果0x8134になったとします)

次に、bun/256とすると0x81と言った風にbunの下から2バイト目を取得することができます。
また、bun%256でbunの下から1バイト目(0x34)を取得します。
かかし さんが書きました:③その下のelse内の「angou=c+(k%256);」は何を意味しているのか?

kを256で割った余りをcに足していますね、もしかしたらこれでangouが256以上にならないようにすることを狙ったのかと思いますが・・・
これでも256を超えてしまう恐れがありますので、(c+k)%256の方が適切なのかもしれません。
(と言ってもこの処理の本来の意図がどういったものかが僕には解らないのでここも先輩に確認するべきでしょう。)

かかし さんが書きました:④「len=i;」は何故あるか?

lenをバイト列長として使用していて、ループ後のiを代入することでバイト列長を移しています。
iの値は以降変わってないので、わざわざlenにiを代入しなくても結構です。
(その場合は以降にあるlenをiに変更しなくてはダメですが・・・)

かかし さんが書きました:⑤「angou[len]=0;」は何故あるか?

これは、末尾に0を入れていますね。
ヌル文字のつもりで入れてるのかと思いますが、
fwrite(angou,len,1,ff);
としてlenバイトしか書き出していないので恐らく不要な処理です。
(そもそもangouは文字列として使用されていないので末尾のヌル文字は必要ないですね。)

[hr][修正]0xff==>0x100
[修正]上位(下位)バイト==>下から2(1)バイト目

かかし

Re: 暗号化について

#3

投稿記事 by かかし » 15年前

丁寧な解説どうもありがとうございます。新たに質問があるのですが

unsigned short int bun;
unsigned char fname[80];
char angou[10000];

のようになっていますが
①なぜ平文を格納する「bun」が unsigned short int 型なのか?(素人の自分としては平文なのでChar型でもいいような気がします。)

次に下のコードですが
②angouとangou[i+1]がどうしてこのような形になるのかわかりません。(「配列」的見地からの解説お願いします)

コード:

	while ((c = fgetc(fp)) != EOF){ 
		if (c >= 0x81 && c <= 0x9F) { 
			if ((c1 = fgetc(fp)) == EOF)break;
			bun=c*256+c1+k; 
			angou[i]=bun/256;------------------------ここと、
			angou[i+1]=bun%256;---------------------ここと、
			i++;
			i++;
		}
		else {
			angou[i]=c+(k%256); ---------------------ここが良くわかりません
			i++;
		}
	}
CODEタグを追加してインデントを修正させていただきました。 by softya(ソフト屋)

自分としては上記の暗号化の部分は
  angou=bun+k
という風に考えてみたのですがどうでしょうか?


③下のfwriteの部分が何を意味しているかわかりません。(自分の解釈としては「ffにangouを書き込む?lenと1は出力する文の長さに関係している?」程度です。)
  fwrite(angou,len,1,ff);

どんなに解説が長くなってもいいので、なるべく詳しく解説お願いします。もし部分的な説明が困難なら、このプログラムの最初からの解説でもかまいません。

ちなみに、このプログラムを実行してみた結果、次のようになりました。

鍵:1
平文:アイウエオ
暗号化した文章:ィゥェォカ

調べてみると「シフトJISの2バイトコード」のエリアマップに対応していて、表の「点方向」(横方向)に1だけシフトしていました。
参考にURLは http://charset.7jp.net/sjis.html

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: 暗号化について

#4

投稿記事 by softya(ソフト屋) » 15年前

本当に理解したいなら、まずC言語の基本的なことを理解されたほうが良いと思います。

①なぜ平文を格納する「bun」が unsigned short int 型なのか?(素人の自分としては平文なのでChar型でもいいような気がします。)

一般的なC言語の処理系でchar型が格納できる数値の範囲をご理解されていますでしょうか?

②angouとangou[i+1]がどうしてこのような形になるのかわかりません。(「配列」的見地からの解説お願いします)

配列的見地と如何なるものでしょうか?
SJISの2バイト文字の1バイト目と2バイト目なのですが。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

non
記事: 1097
登録日時: 15年前

Re: 暗号化について

#5

投稿記事 by non » 15年前

暗号化されたファイルをテキストで表示しても意味がありませんよ。今回はたまたま、文字として出力されただけです。
バイナリエディタを使いましょう。

「窓の杜」でお好きなバイナリエディタをダウンしましょう。ちなみに、私はBzを使ってます。
non

アバター
bitter_fox
記事: 607
登録日時: 15年前
住所: 大阪府

Re: 暗号化について

#6

投稿記事 by bitter_fox » 15年前

かかし さんが書きました:

コード:

unsigned short int bun;
unsigned char fname[80];
char angou[10000];
①なぜ平文を格納する「bun」が unsigned short int 型なのか?(素人の自分としては平文なのでChar型でもいいような気がします。)
bunには平文は格納されません。
平文が格納されるのはc, c1です。
また、bunがunsigned short int型なのは、
c*256+c1+k
が代入されるためです。
かかし さんが書きました:②angouとangou[i+1]がどうしてこのような形になるのかわかりません。(「配列」的見地からの解説お願いします)

コード:

while ((c = fgetc(fp)) != EOF){ 
	if (c >= 0x81 && c <= 0x9F) { 
		if ((c1 = fgetc(fp)) == EOF)
			break;
		bun=c*256+c1+k; 
		angou[i]=bun/256;------------------------ここと、
		angou[i+1]=bun%256;---------------------ここと、
		i++;
		i++;
	}
}
配列的見地が何かが全く分からないですが・・・

コード:

 --------------------------------------------------------------------
| ア | イ | ウ | エ | オ |                                           |
 --------------------------------------------------------------------
これを十六進数で表現すると(本当は0xが数字の前にある)
 --------------------------------------------------------------------
|8341|8343|8345|8347|8349|                                           |
 --------------------------------------------------------------------
と言った風になります。

これを読み込むと次のようになります。
 --------------------------------------------------------------------
| c|c1| c|c1| c|c1| c|c1|                                            |
|83|41|83|43|83|45|83|49|                                            |
 --------------------------------------------------------------------

本来二バイトなので、次のようにしてつなげます。

c*256+c1
こうすることで、
----------------------------------------------------------------------
| bun | 0x8341
| bun | 0x8343
| bun | 0x8345
| bun | 0x8347
| bun | 0x8349
----------------------------------------------------------------------
となり、さらに暗号キーを足します。(説明のために暗号キーを1とします)
----------------------------------------------------------------------
| bun | 0x8342
| bun | 0x8344
| bun | 0x8346
| bun | 0x8348
| bun | 0x834A
----------------------------------------------------------------------

そして、bun/256が
----------------------------------------------------------------------
| bun / 256 | 0x83
| bun / 256 | 0x83
| bun / 256 | 0x83
| bun / 256 | 0x83
| bun / 256 | 0x83
----------------------------------------------------------------------
となって。

bun%256が
----------------------------------------------------------------------
| bun % 256 | 0x42
| bun % 256 | 0x44
| bun % 256 | 0x46
| bun % 256 | 0x48
| bun % 256 | 0x4A
----------------------------------------------------------------------
となります。

これをangouに代入していくと
-----------------------------------------------------------------------
|angou                                                                 |
| i |i+1| i |i+1| i |i+1| i |i+1| i |i+1|                              |
| 83| 42| 83| 44| 83| 46| 83| 48| 83| 4A|                              |
-----------------------------------------------------------------------
となり、これをSJISとして文字にすると。

 --------------------------------------------------------------------
| ィ | ゥ | ェ | ォ | カ |                                           |
 --------------------------------------------------------------------
となりました。
かかし さんが書きました:

コード:

	else {
		angou[i]=c+(k%256); ---------------------ここが良くわかりません
		i++;
	}
自分としては上記の暗号化の部分は
  angou=bun+k
という風に考えてみたのですがどうでしょうか?

ここは暗号アルゴリズムによって変わってくるのでどういった暗号アルゴリズムなのか(と言うか暗号の仕様)がはっきりしないことには判断できないですね・・・


かかし さんが書きました:③下のfwriteの部分が何を意味しているかわかりません。(自分の解釈としては「ffにangouを書き込む?lenと1は出力する文の長さに関係している?」程度です。)
  fwrite(angou,len,1,ff);

fwriteは第四引数に指定されたファイルポインタがさすファイルに第一引数の内容を第三引数で指定したバイト数の物を第二引数個書き込みます。
http://www9.plala.or.jp/sgwr-t/lib/fwrite.html

あと、この暗号だと復元するのは難しいように感じるのですが・・・

閉鎖

“C言語何でも質問掲示板” へ戻る