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

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

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

Objective-Cはオブジェクト指向型のプログラミング言語のひとつです。C言語をベースにSmalltalkが取り入れられています。

C#

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

iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

ASP.NET

ASP.NETは動的なWebサイトやWebアプリケーション、そしてWebサービスを構築出来るようにする為、Microsoftによって開発されたウェブアプリケーション開発フレームワークです。

Q&A

解決済

2回答

5545閲覧

iOSアプリからのPOST送信の暗号化についてのエラー

konryu304

総合スコア8

Objective-C

Objective-Cはオブジェクト指向型のプログラミング言語のひとつです。C言語をベースにSmalltalkが取り入れられています。

C#

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

iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

ASP.NET

ASP.NETは動的なWebサイトやWebアプリケーション、そしてWebサービスを構築出来るようにする為、Microsoftによって開発されたウェブアプリケーション開発フレームワークです。

0グッド

0クリップ

投稿2017/01/23 01:19

###前提・実現したいこと
iOSアプリでwebサーバにPOST送信するアプリを作成しております。
POSTの際にAES256により暗号化(その後、base64でエンコード)を行なっているのですが、特定のデータで復元に失敗します。
(特定のデータで復元ができているため、暗号化キー、初期化ベクトルの設定は問題ないと思われる。)
確証はないのですが、文字コードの設定などが怪しいのではないかと考えております。

###発生している問題・エラーメッセージ

サーバ側(C# ASP.net、IIS8.0) Base-64 文字配列または文字列の長さが無効です。

###クライアント側(iOS)のソースコード

Objective

1- (void)postInputData:(NSData *)query 2{ 3 NSString *url = @"URL"; 4 5 //リクエストの種類、ヘッダを設定する 6 NSMutableURLRequest *request = [NSMutableURLRequest 7 requestWithURL: [NSURL URLWithString: url] 8 cachePolicy: NSURLRequestUseProtocolCachePolicy 9 timeoutInterval: TIMEOUT_SECOND]; 10 11 [request setHTTPMethod: @"POST"]; 12 [request setValue: @"application/x-www-form-urlencoded" forHTTPHeaderField: @"Content-Type"]; 13 [request setValue: [NSString stringWithFormat: @"%lu", (unsigned long)[query length]] forHTTPHeaderField: @"Content-Length"]; 14 [request setHTTPBody: query]; 15 16 //共有セッションを取得し、サーバにリクエストを行う 17 NSURLSession *session = [NSURLSession sharedSession]; 18 19 [[session dataTaskWithRequest: request completionHandler: ^(NSData *data, NSURLResponse *response, NSError *error) { 20 21 //レスポンスを確認 22 NSString *responseString = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding]; 23 24 }] resume]; 25} 26 27- (NSData *) buildQuery:(NSData *)imageData 28{ 29 NSString *const FIRST_POST_FORMAT = @"=%@="; 30 NSString *const POST_FORMAT = @"%@="; 31 32 //項目名を追加 33 NSMutableArray *paramCodeArray = [NSMutableArray array]; 34 [paramCodeArray addObject:[NSString stringWithFormat:FIRST_POST_FORMAT, @“No”]]; 35 [paramCodeArray addObject:[NSString stringWithFormat:POST_FORMAT, @“name”]]; 36 37 //値を追加 38 NSMutableArray *paramValueArray = [NSMutableArray array]; 39 [paramValueArray addObject:@“1234567”]]; 40 [paramValueArray addObject:@“佐藤 一郎”]; 41 42 NSMutableData *query = [NSMutableData data]; 43 for (int paramNo = 0; paramNo < paramCodeArray.count; paramNo++) 44 { 45 //項目名(NSData)を追加 46 [query appendData:[self convertPostData:paramCodeArray[paramNo] 47 encyiptFlg:NO]]; 48 49 //値を追加 50 [query appendData:[self convertPostData:paramValueArray[paramNo] 51 encyiptFlg:YES]]; 52 53 if (paramNo != paramCodeArray.count - 1) 54 { 55 [query appendData:[self convertPostData:@"," encyiptFlg:NO]]; 56 } 57 } 58 59 return query; 60} 61 62- (NSData *)convertPostData: (NSString *)str encyiptFlg:(BOOL)encyiptFlg 63{ 64 NSData *query; 65 66 if (encyiptFlg == YES) 67 { 68 query = [str dataUsingEncoding: NSShiftJISStringEncoding]; 69 //①queryをAES256で暗号化 70 query = [query AES256EncryptWithKey:AES256KEY]; 71 72 //②queryをbase64に変換 73 query = [query base64EncodedDataWithOptions:NSDataBase64Encoding64CharacterLineLength]; 74 } 75 else 76 { 77 query = [str dataUsingEncoding: NSShiftJISStringEncoding]; 78 } 79 return query; 80} 81 82以下、NSDataへ追加しています 83- (NSData *)AES256EncryptWithKey:(NSString *)key { 84 // 'key' should be 32 bytes for AES256, will be null-padded otherwise 85 char keyPtr[kCCKeySizeAES256+1]; 86 bzero(keyPtr, sizeof(keyPtr)); 87 88 [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding]; 89 90 char ivPtr[kCCKeySizeAES128+1]; 91 bzero(ivPtr, sizeof(ivPtr)); 92 [IV getCString:ivPtr maxLength:sizeof(ivPtr) encoding:NSUTF8StringEncoding]; 93 94 95 NSUInteger dataLength = [self length]; 96 97 size_t bufferSize = dataLength + kCCBlockSizeAES128; 98 void *buffer = malloc(bufferSize); 99 100 size_t numBytesEncrypted = 0; 101 CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, 102 keyPtr, kCCKeySizeAES256,//kCCKeySizeAES256, 103 ivPtr /* initialization vector (optional) */, //NULL 104 [self bytes], dataLength, /* input */ 105 buffer, bufferSize, /* output */ 106 &numBytesEncrypted); 107 if (cryptStatus == kCCSuccess) { 108 return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted]; 109 } 110 111 free(buffer); //free the buffer; 112 return nil; 113}

###サーバ側(C# APS.net)のソースコード

C#

1 //ブロックサイズ 2 private const int aesBlockSize = 128; 3 //鍵長 4 private const int aesKeySize = 256; 5 //エンコーディング 6 private static Encoding aesEncoding = Encoding.GetEncoding("shift_jis"); 7 8 //POST 9 public string Post([FromBody]string value) 10 { 11 try 12 { 13 string text = string.Empty; 14 //バイト型配列に戻す 15 if (value != null && value != string.Empty) 16 { 17 // 取得した日付を表示する 18 string strDate = DateTime.Now.ToString("yyyyMMddHHmmss"); 19 string pathStr = @"D:\postTest" + strDate + ".txt"; 20 21 //テキストファイルに書き込み 22 using (StreamWriter writer = new StreamWriter(pathStr, true, System.Text.Encoding.GetEncoding("shift_jis"))) 23 { 24 //カンマ区切りで分割して配列に格納する 25 string[] postData = value.Split(','); 26 27 for (int i = 0; i < postData.Length; i++) 28 { 29 /*---------------POSTデータ分解処理---------------*/ 30 //「No=1234567」の形に取り出す 31 string oneReq = postData[i]; 32 //key(例:No)の部分を取り出す 33 string[] oneReqArray = oneReq.Split('='); 34 string key = oneReqArray[0]; 35 //keyを削除する 36 string reqValue = oneReq.Remove(0, key.Length + 1); 37 /*---------------POSTデータ分解処理---------------*/ 38 39 /*--------------aes256復元処理(base64のデコードも)--------------*/ 40 string hukugouStr = ValuesController.AesDecrypt(reqValue, Aes256Key); 41 /*--------------aes256復元処理--------------*/ 42 43 //復元した値を書込み 44 writer.WriteLine(key + " : " + hukugouStr); 45 } 46 } 47 return "OK"; 48 } 49 //値が空の場合、エラーとする。 50 else 51 { 52 // 取得した日付を表示する 53 string strDate2 = DateTime.Now.ToString("yyyyMMddHHmmss"); 54 string pathStr2 = @"D:\postTest" + strDate2 + ".txt"; 55 using (StreamWriter writer = new StreamWriter(pathStr2, true, System.Text.Encoding.UTF8)) 56 { 57 writer.WriteLine("空でした。"); 58 } 59 return "NG" 60 } 61 } 62 } 63 64 /// <summary> 65 /// 指定した鍵で復号化 66 /// </summary> 67 /// <param name="source">復号対象文字列</param> 68 /// <param name="key">鍵</param> 69 public static string AesDecrypt(string source, string key) 70 { 71 using (var provider = CreateAesProvider(key)) 72 { 73 var sourceBytes = Convert.FromBase64String(source); 74 using (var decryptor = provider.CreateDecryptor()) 75 { 76 var retBytes = decryptor.TransformFinalBlock(sourceBytes, 0, sourceBytes.Length); 77 return aesEncoding.GetString(retBytes); 78 } 79 } 80 } 81 82 /// <summary> 83 /// AESプロバイダー生成 84 /// </summary> 85 /// <param name="key">鍵</param> 86 private static AesCryptoServiceProvider CreateAesProvider(string key) 87 { 88 var provider = new AesCryptoServiceProvider(); 89 provider.BlockSize = aesBlockSize; 90 provider.KeySize = aesKeySize; 91 provider.IV = aesEncoding.GetBytes(aes256IV); 92 provider.Key = aesEncoding.GetBytes(key); 93 provider.Mode = CipherMode.CBC; 94 provider.Padding = PaddingMode.PKCS7; 95 return provider; 96 }

###試したこと
下記の事項は検証いたしました。
①暗号化なしでは正常に送信できること。
②Base64のエンコードのみでは正常に送信できること。
③AES256で暗号化、その後base64でエンコードした際、特定のデータでは送信できること。
※エラーはBase64から復元できないと書いてあります

###補足情報(言語/FW/ツール等のバージョンなど)
言語:クライアント側:Objective-c
サーバ側:C#、ASP.net
OS:クライアント側:iOS10.2
サーバ側:Windows Server 2012

クライアント側、サーバ側と両方関係があると思われるため、原因の特定ができずにいます。
些細な情報でも構いませんので、アドバイスを頂ければ幸いです。
よろしくお願いいたします。

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

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

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

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

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

guest

回答2

0

自己解決

自力で解決いたしました。
原因はbase64変換後のPOSTデータに空白が含まれていたためでした。
string henkan = reqValue.Replace(" ", "+");
サーバ側にて上記の置換処理を入れた後にbase64で復号して上手くいきました。
今回は情報を提供してくださった方をベストアンサーといたします。
ご協力ありがとうございました。

投稿2017/01/23 05:45

konryu304

総合スコア8

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

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

fuzzball

2017/01/23 06:18

解決した方法(この回答)をベストアンサーにした方がいいと思いますよ。
konryu304

2017/01/23 07:10

申し訳ございません。 変更ができないと思われるので次回より気をつけます。 ありがとうございました。
fuzzball

2017/01/23 07:13

変更は出来ます。
guest

0

エラーメッセージでちょっとググっただけですが、

http://anti.rosx.net/etc/memo/006_air_shodo.html#A02

「Base-64 文字配列または文字列の長さが無効です。」で調べても特に該当しそうな解決策は見つからない。

英語だと「Invalid length for a Base-64 char array.」と言うらしいのでそちらで調べたものの変わらず。
30分ほど時間を食いつぶした挙句に原因が判明。textBoxの文字数制限に引っ掛かっているだけだった。

投稿2017/01/23 01:30

fuzzball

総合スコア16731

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問