質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

1回答

200閲覧

gcry_mpi_t 内の公開鍵をビット列で取り出したい

yamahiroto

総合スコア7

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2017/11/03 15:27

gcry_mpi_t 内の公開鍵をビット列で取り出したい

libgcrypt1.7.6 を使ってRSA暗号をいじってく中で,
gcry_mpi_t型におさまっている公開鍵をビット列で取り出したいです.
(libgcrypt1.7.6を対象とするテスト用なのでこのバージョンで実行したいです)

char型の鍵をgcry_mpi_t型に入れることはできるんですが,その逆がうまくいきません.
つまりgcry_mpi_t型の公開鍵eをchar型にして取り出すとなぜか文字列が変わります.

###発生している問題・エラーメッセージ
公開鍵eについてサンプル値「0x010001」を使って,一度gcry_mpi_t型に変えた後.
再びchar型として取り出すとなぜか「0x000001」に代わってしまいます.

※ちなみにchar型からgcry_mpi_t型に戻すとこれは正しく「0x010001」になってます.

###該当のソースコード

c

1#include "gcry.h" 2 3/* A sample 2048 bit RSA key used for the selftests (public only). */ 4static const char sample_public_key[] = 5" (public-key" 6" (rsa" 7" (n #009F56231A3D82E3E7D613D59D53E9AB921BEF9F08A782AED0B6E46ADBC853EC" 8" 7C71C422435A3CD8FA0DB9EFD55CD3295BADC4E8E2E2B94E15AE82866AB8ADE8" 9" 7E469FAE76DC3577DE87F1F419C4EB41123DFAF8D16922D5EDBAD6E9076D5A1C" 10" 958106F0AE5E2E9193C6B49124C64C2A241C4075D4AF16299EB87A6585BAE917" 11" DEF27FCDD165764D069BC18D16527B29DAAB549F7BBED4A7C6A842D203ED6613" 12" 6E2411744E432CD26D940132F25874483DCAEECDFD95744819CBCF1EA810681C" 13" 42907EBCB1C7EAFBE75C87EC32C5413EA10476545D3FC7B2ADB1B66B7F200918" 14" 664B0E5261C2895AA28B0DE321E921B3F877172CCCAB81F43EF98002916156F6CB#)" 15" (e #010001#)))"; 16 17 18int main(int argc, char** argv){ 19 gcry_error_t err = 0; 20 gcry_sexp_t pkey = NULL; 21 22 23 /* Covert the S-expressions into the internal representation. */ 24 err = gcry_sexp_sscan(&pkey, NULL, 25 sample_public_key, strlen(sample_public_key)); 26 if (err){ 27 xerr("failed to scan sample key."); 28 return 1; 29 } 30 31 32 /* pkey compornents */ 33 gcry_sexp_t e_pkey = gcry_sexp_find_token(pkey, "e", 0); 34 gcry_mpi_t expo_pkey = gcry_sexp_nth_mpi(e_pkey, 1, GCRYMPI_FMT_USG); 35 36 37 /*Dump MPIs */ 38 printf("### Dump MPIs ###\n"); 39 printf("pkey expo\n"); 40 gcry_mpi_dump(expo_pkey); 41 printf("\n"); 42 43 44 /* bit length */ 45 printf("### bit length ###\n"); 46 unsigned int expo_len = gcry_mpi_get_nbits(expo_pkey); 47 printf("expo_pkey :\t%d\n", expo_len); 48 49 50 /* mpi_print */ 51 printf("### mpi print command ###\n"); 52 printf("mpi_print\n"); 53 unsigned char* expo; 54 expo = (unsigned char*)malloc(3); 55 if (expo == NULL){ 56 printf("expo is NULL\n"); 57 return 1; 58 } 59 err = gcry_mpi_print(GCRYMPI_FMT_USG, expo, 3, NULL, expo_pkey); 60 if (err){ 61 xerr("failed: expo MPI_print"); 62 } 63 64 65 /* check print */ 66 gcry_mpi_t res; 67 size_t size; 68 err = gcry_mpi_scan(&res, GCRYMPI_FMT_USG, 69 expo, 3, &size); 70 if (err){ 71 xerr("failed to scan res"); 72 } 73 printf("check mpi print\n"); 74 gcry_mpi_dump(res); 75 printf("\n"); 76 // bit print 77 printf("\n"); 78 printf("### bit sequance ###\n"); 79 printf("%4u\t%02x\n", *expo, *expo); 80 for (int i = expo_len-1; i >= 0; i--){ 81 printf("%d", (*(expo)>>i) & 1); 82 if (i % 4 == 0){ 83 printf(" "); 84 } 85 } 86 printf("\n"); 87} 88

出力はこんな感じです↓↓

### Dump MPIs ### pkey expo 010001 //これが正しい鍵値 ### bit length ### expo_pkey: 17 //ビット長 ### mpi print command ### mpi_print check mpi print 010001 //char型で取り出した鍵をもう一度gcry_mpi_t型に戻してdumpしたもの ### bit sequance ### 1 01 0 0000 0000 0000 0001 // 最上位ビットが「1」のはずだがならない

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

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

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

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

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

guest

回答1

0

ベストアンサー

再びchar型として取り出すとなぜか「0x000001」に代わってしまいます.

変わっている訳ではなく、3バイトのexpoをダンプする以下のコードに問題があります。

C

1 printf("%4u\t%02x\n", *expo, *expo); 2 for (int i = expo_len-1; i >= 0; i--){ 3 printf("%d", (*(expo)>>i) & 1); 4 if (i % 4 == 0){ 5 printf(" "); 6 } 7 }

expoはmalloc(3)で割り当てられたunsigned charの3バイトの配列ですが、*(expo)としている為、expo[0], expo[1], expo[2] と、ビット位置に応じて正しく参照できていません。

以下のコードにすることで、正しくダンプできます。(3バイトのビッグエンディアンを前提としています)

C

1#define EXPO_LEN 3 2 3 for (int i = expo_len - 1; i >= 0; i--) { 4 5 // ビット位置に応じて、参照すべきexpo[n]のインデックスnを求める。 6 int array_index = EXPO_LEN - ((i + 8) / 8); 7 8 // 参照すべきビットの位置を求める。 9 int bit_index = i % 8; 10 11 // 参照すべきexpo[n]を取得 12 unsigned char target_byte = *(expo + array_index); 13// printf("%d: %02X, bit_index=%d\n", array_index, target_byte, bit_index); 14 15 int bit = (((target_byte >> bit_index) & 1) != 0) ? 1: 0; 16 printf("%d", bit); 17 if (i % 4 == 0) { 18 printf(" "); 19 } 20 }

一応、テストしたコードを全掲載します。gcry.h とxerr()関数はおそらく質問者様が
独自に用意されたものだと思いましたので、改変しています。

//sample.c //#include "gcry.h" #include "gcrypt.h" #define xerr(v) int test3(void); int main(int argc, char** argv){ test3(); return 0; } #define EXPO_LEN 3 /* A sample 2048 bit RSA key used for the selftests (public only). */ static const char sample_public_key[] = " (public-key" " (rsa" " (n #009F56231A3D82E3E7D613D59D53E9AB921BEF9F08A782AED0B6E46ADBC853EC" " 7C71C422435A3CD8FA0DB9EFD55CD3295BADC4E8E2E2B94E15AE82866AB8ADE8" " 7E469FAE76DC3577DE87F1F419C4EB41123DFAF8D16922D5EDBAD6E9076D5A1C" " 958106F0AE5E2E9193C6B49124C64C2A241C4075D4AF16299EB87A6585BAE917" " DEF27FCDD165764D069BC18D16527B29DAAB549F7BBED4A7C6A842D203ED6613" " 6E2411744E432CD26D940132F25874483DCAEECDFD95744819CBCF1EA810681C" " 42907EBCB1C7EAFBE75C87EC32C5413EA10476545D3FC7B2ADB1B66B7F200918" " 664B0E5261C2895AA28B0DE321E921B3F877172CCCAB81F43EF98002916156F6CB#)" " (e #010001#)))"; int test3(void) { gcry_error_t err = 0; gcry_sexp_t pkey = NULL; /* Covert the S-expressions into the internal representation. */ err = gcry_sexp_sscan(&pkey, NULL, sample_public_key, strlen(sample_public_key)); if (err){ xerr("failed to scan sample key."); return 1; } /* pkey compornents */ gcry_sexp_t e_pkey = gcry_sexp_find_token(pkey, "e", 0); gcry_mpi_t expo_pkey = gcry_sexp_nth_mpi(e_pkey, 1, GCRYMPI_FMT_USG); /*Dump MPIs */ printf("### Dump MPIs ###\n"); printf("pkey expo\n"); gcry_mpi_dump(expo_pkey); printf("\n"); /* bit length */ printf("### bit length ###\n"); unsigned int expo_len = gcry_mpi_get_nbits(expo_pkey); printf("expo_pkey :\t%d\n", expo_len); /* mpi_print */ printf("### mpi print command ###\n"); printf("mpi_print\n"); unsigned char* expo; expo = (unsigned char*)malloc(EXPO_LEN); if (expo == NULL){ printf("expo is NULL\n"); return 1; } err = gcry_mpi_print(GCRYMPI_FMT_USG, expo, EXPO_LEN, NULL, expo_pkey); if (err){ xerr("failed: expo MPI_print"); } /* check print */ gcry_mpi_t res; size_t size; err = gcry_mpi_scan(&res, GCRYMPI_FMT_USG, expo, EXPO_LEN, &size); if (err){ xerr("failed to scan res"); } printf("check mpi print\n"); gcry_mpi_dump(res); printf("\n"); // bit print printf("\n"); printf("### bit sequance ###\n"); printf("%4u\t%02x\n", *expo, *expo); // printf("%02X, %02X, %02X\n", *(expo + 0), *(expo + 1), *(expo + 2)); for (int i = expo_len - 1; i >= 0; i--) { // ビット位置に応じて、参照すべきexpo[3]のインデックスを求める。 int array_index = EXPO_LEN - ((i + 8) / 8); // 参照すべきビットの位置を求める。 int bit_index = i % 8; // 参照すべきexpo[n]を取得 unsigned char target_byte = *(expo + array_index); // printf("%d: %02X, bit_index=%d\n", array_index, target_byte, bit_index); int bit = (((target_byte >> bit_index) & 1) != 0) ? 1: 0; printf("%d", bit); if (i % 4 == 0) { printf(" "); } } printf("\n"); return 0; }

Cygwin32ビット上での実行結果です。gcrypt はlibgcrypt1.7.6を用意できなかったので1.7.8 ですが、
今回の件には問題無いと思います。

Bash

1$ gcc -Wall sample.c -lgcrypt 2 3$ ./a.exe 4### Dump MPIs ### 5pkey expo 6010001 7### bit length ### 8expo_pkey : 17 9### mpi print command ### 10mpi_print 11check mpi print 12010001 13 14### bit sequance ### 15 1 01 161 0000 0000 0000 0001 17

投稿2017/11/04 08:53

dodox86

総合スコア9183

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

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

yamahiroto

2017/11/04 11:17

回答ありがとうございます! 無事問題解決ができました.ポインタあたりがまだしっかり理解できていなかったのでとても勉強になりました.
dodox86

2017/11/04 12:07

経過のご報告ありがとうございます。他の例ですが、4バイト迄のデータであれば例えばunsigned longの変数1つにパックして、変数1つでビット演算するほうがループをまわすのも簡単になって良いこともあります。場合に応じてどうぞ。 例: int main() { unsigned char array[3] = { 0x81, 0x23, 0x45 }; unsigned char* expo = array; unsigned long ul = *expo << 16 | *(expo + 1) << 8 | *(expo + 2); printf("ul=0x%08lX\n", ul); return 0; } 実行結果 ul=0x00812345
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問