備忘録

備忘録

C#でRSAの暗号化と復号を行う方法

Ⅰ. はじめに

タイトルの通り「C#RSAの暗号化と復号を行う方法」です。
サンプルプログラムとして扱うRSA暗号の詳細は以下の表の通りです。

アルゴリズム RSA
KeySize 1024bit
モード ECB
パディング OAEPWithSHA1AndMGF1Padding

Ⅱ. サンプルプログラム

.NET標準ライブラリを使う方法
private byte[] RSAEncrypt(byte[] modulus, byte[] exponent, byte[] bytes)
{
  // RSA/ECB/OAEPWithSHA1AndMGF1Padding
  using (var rsa = new RSACryptoServiceProvider())
  {
    rsa.ImportParameters(new RSAParameters
    {
      Modulus = modulus,
      Exponent = exponent
    });
    
    return rsa.Encrypt(bytes, true);

    // 復号する時
    // rsa.Decrypt(bytes, true);
  }
}
BouncyCastleを使う方法
Install-Package Portable.BouncyCastle
private byte[] RSAEncrypt(byte[] modulus, byte[] exponent, byte[] bytes)
{
  // RSA/ECB/OAEPWithSHA1AndMGF1Padding
  var key = new RsaKeyParameters(false, new BigInteger(1, modulus), new BigInteger(1, exponent));
  var cipher = new OaepEncoding(new RsaEngine(), new Sha1Digest());
  cipher.Init(true, key);

  // 復号する時
  // cipher.Init(false, key);
  
  int blockSize = cipher.GetInputBlockSize();
  var encryptedBytes = new List<byte>();
  for (int chunkPosition = 0; chunkPosition < bytes.Length; chunkPosition += blockSize)
  {
    var chunkLength = Math.Min(blockSize, bytes.Length - chunkPosition);
    encryptedBytes.AddRange(cipher.ProcessBlock(bytes, chunkPosition, chunkLength));
  }
  
  return encryptedBytes.ToArray();
}

Ⅲ. 鍵を読み込む方法

1. 秘密鍵、公開鍵を作成する
$ openssl genrsa -out private 2048
$ openssl rsa -in private -pubout -out public
$ cat public
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvJQMzl0SEKfxmRmzvkxa
X8vA11xyUcK4cwwyp6+lrULF/kmRN/xwWGXSG5sIOvCXKo9DnC8uQpNf60nFFPMZ
WoSHahfvz+QbY2usWkRAoO5l18ET1U2+035V32W7NqIvDEi9klMybmP9qyOFAfHO
xGphOpM7qrjoTC00KY3WILyaj0Qj/b00sghxx89Ud/rq5D995CVOf6O88mtRUEZ6
TY8SSiuxevPj8str96lLQLParb0Eja8mIz2aEf1O1og0IUlj3+X7sTY8mhjNMKKe
xws7QlrcGHJenTzi2Y11P/oKFljRBMMVvXscItX+wc1WRKQxktMlqqNTzNbmWR4f
owIDAQAB
-----END PUBLIC KEY-----
2. サンプルプログラムを書く

Program.cs

var publicKey = File.ReadAllText("public");

var rsa = RSA.Create();
rsa.ImportFromPem(publicKey);
var parameters = rsa.ExportParameters(false);
Console.WriteLine(BitConverter.ToString(parameters.Modulus!).Replace("-", " "));
Console.WriteLine(BitConverter.ToString(parameters.Exponent!).Replace("-", " "));
実行結果
BC 94 0C CE 5D 12 10 A7 F1 99 19 B3 BE 4C 5A 5F CB C0 D7 5C 72 51 C2 B8 73 0C 32 A7 AF A5 AD 42 C5 FE 49 91 37 FC 70 58 65 D2 1B 9B 08 3A F0 97 2A 8F 43 9C 2F 2E 42 93 5F EB 49 C5 14 F3 19 5A 84 87 6A 17 EF CF E4 1B 63 6B AC 5A 44 40 A0 EE 65 D7 C1 13 D5 4D BE D3 7E 55 DF 65 BB 36 A2 2F 0C 48 BD 92 53 32 6E 63 FD AB 23 85 01 F1 CE C4 6A 61 3A 93 3B AA B8 E8 4C 2D 34 29 8D D6 20 BC 9A 8F 44 23 FD BD 34 B2 08 71 C7 CF 54 77 FA EA E4 3F 7D E4 25 4E 7F A3 BC F2 6B 51 50 46 7A 4D 8F 12 4A 2B B1 7A F3 E3 F2 CB 6B F7 A9 4B 40 B3 DA AD BD 04 8D AF 26 23 3D 9A 11 FD 4E D6 88 34 21 49 63 DF E5 FB B1 36 3C 9A 18 CD 30 A2 9E C7 0B 3B 42 5A DC 18 72 5E 9D 3C E2 D9 8D 75 3F FA 0A 16 58 D1 04 C3 15 BD 7B 1C 22 D5 FE C1 CD 56 44 A4 31 92 D3 25 AA A3 53 CC D6 E6 59 1E 1F A3
01 00 01

mitmproxyとarpspoofを利用してスマートフォン(Android/iOS)のHTTP(s)通信を見る方法

Ⅰ. はじめに

タイトルの通り「mitmproxyとarpspoofを利用してスマートフォン(Android/iOS)のHTTP(s)通信を見る方法」です。

Ⅲ. やり方

1. IPフォワードを有効にする
echo 1 > /proc/sys/net/ipv4/ip_forward
2. ルーティングを変更する

HTTP(80), HTTPS(443)にきたパケットを全てmitmproxy(8080)にリダイレクトします。

iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8080
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -j REDIRECT --to-port 8080
3. ARPスプーフィングを行う
ターゲット(スマートフォン 192.168.0.7
デフォルトゲートウェイ 192.168.0.1

この環境の場合以下のコマンドになります。

arpspoof -t 192.168.0.7 192.168.0.1
4. mitmproxyを透過型として起動する
mitmproxy -T --host --ignore 'crashlytics\.com:443'
5. ルート証明書(mitmproxy-ca-cert.pem)をスマートフォンにインストールする

http://mitm.it にアクセスするとルート証明書のインストール画面が表示されます。

6. ログがmitmproxyの画面に表示される


Ⅳ. Android 7以降について

Android 7(Nougat)以降はセキュリティの為ユーザが任意でインストールした証明書がデフォルトで読み込まれなくなりました。

自作アプリケーションの場合

android:networkSecurityConfig をAndroidManifest.xml で設定するとユーザの証明書が読み込まれるようになります。

その他アプリケーションの場合

APKを逆コンパイルし、AndroidManifest.xmlに変更を加える事でユーザの証明書が読み込まれるようになります。
また、root権限が使える場合は以下のコマンドを実行する事によりユーザー証明書ではなくシステム証明書として認識させる事で回避可能です。

cp /data/misc/user/0/cacerts-added/* /system/etc/security/cacerts/

また、これを自動化したMagisk用モジュールが公開されています。
https://github.com/NVISO-BE/MagiskTrustUserCerts

※Magiskモジュールに関する注意点
Magisk Hide使用時は本記事のようなMITMとして利用する場合期待する動作になりません。
手動でシステム証明書として認識させる事を推奨します。
Magiskモジュールは以下のようにMagiskの特殊な領域に証明書をコピーしています。

# https://github.com/NVISOsecurity/MagiskTrustUserCerts/blob/9c8b955e4b91237becb9ee3b15c15ce5ead97e8e/post-fs-data.sh#L8
cp -f /data/misc/user/0/cacerts-added/* $MODDIR/system/etc/security/cacerts/

実際の/system/etc/security/cacerts/にはコピーされていない為Magisk Hide有効時はルート証明書が期待する形で読み取られません。

その他

Proxy設定
adb shell settings put global http_proxy 192.168.0.2:8008
Proxy設定解除
adb shell settings put global http_proxy :0

WindowsでHyper-V用Kali Linuxをインストールする方法

Ⅰ. はじめに

今回はKali Linux公式HPで公開されているHyper-V用のイメージを利用します。
予めHyper-Vを有効にする必要があります。
http://kagasu.hatenablog.com/entry/2016/09/24/192659

Ⅱ. やり方

1. Hyper-V用Kali Linuxのイメージをダウンロードする

https://www.kali.org/downloads/

2. Hyper-Vマネージャーを起動し、「仮想マシンのインポート」をクリックする

f:id:kagasu:20180120084715p:plain

3. 新しい仮想スイッチを作成し、外部ネットワークにチェックを入れる

f:id:kagasu:20180120085200p:plain

4. 仮想マシンの設定を開き、仮想スイッチとして「3で作成したスイッチ」を選択する。

f:id:kagasu:20180120085419p:plain

5. Kali Linuxを起動しサインインする
Username root
Password toor
6. IPアドレスが割り当てられている事を確認する

f:id:kagasu:20180120085822p:plain

7. SSHでrootログインを有効にする

/etc/ssh/sshd_confing

PermitRootLogin yes
8. SSHサーバを起動する
systemctl start ssh
9. SSHクライアントから接続をテストする

f:id:kagasu:20180120090522p:plain

C#でローカルIPアドレスを列挙する方法

Ⅰ. はじめに

タイトルの通り「C#でローカルIPアドレスを列挙する方法」です。

Ⅱ. サンプルプログラム

Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;

namespace GetIPAddressesExample
{
  class Program
  {
    static IEnumerable<IPAddress> GetIPAddresses(bool excludeLocalHost = false, bool excludeIPv6 = false)
    {
      var ipaddresses = NetworkInterface
        .GetAllNetworkInterfaces()
        .Where(x => x.OperationalStatus == OperationalStatus.Up)
        .SelectMany(x => x
          .GetIPProperties()
          .UnicastAddresses
          .Select(y => y.Address));

      if (excludeLocalHost)
      {
        ipaddresses = ipaddresses
          .Where(x => !x.Equals(IPAddress.Parse("127.0.0.1")))
          .Where(x => !x.Equals(IPAddress.Parse("::1")));
      }

      if (excludeIPv6)
      {
        ipaddresses = ipaddresses
          .Where(x => x.AddressFamily != AddressFamily.InterNetworkV6);
      }

      return ipaddresses;
    }

    static void Main(string[] args)
    {
      foreach (var x in GetIPAddresses())
      {
        Console.WriteLine(x);
      }

      Console.WriteLine("ローカルホストを省く");
      foreach (var x in GetIPAddresses(excludeLocalHost: true))
      {
        Console.WriteLine(x);
      }

      Console.WriteLine("IPv6を省く");
      foreach (var x in GetIPAddresses(excludeIPv6: true))
      {
        Console.WriteLine(x);
      }
    }
  }
}

Ⅲ. 実行結果

f:id:kagasu:20180115185143p:plain