整数オーバーフローと符号エラー
整数に関係するバグについてのメモ。
環境
Ubuntu 14.04.4 LTS 64bit版
$ uname -a Linux vm-ubuntu64 3.19.0-25-generic #26~14.04.1-Ubuntu SMP Fri Jul 24 21:16:20 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux $ lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 14.04.4 LTS Release: 14.04 Codename: trusty $ gcc --version gcc (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4
整数オーバーフロー(Integer Overflow)
整数オーバーフローは、演算の結果、整数が表現できる最大値を越えてしまうことにより発生するバグである。
/* integer_overflow.c */ #include <stdio.h> #include <stdlib.h> int main() { char buf[40]; int n; scanf("%d", &n); printf("n+1 == %d\n", n+1); if (n+1 > sizeof(buf)) { puts("too long!"); exit(1); } read(0, buf, n); return 0; }
上のコードではバッファサイズのチェックが行われているが、次のように4294967295(=232-1)を与えたときチェックを通過してしまう。
$ gcc integer_overflow.c $ ./a.out 10 n+1 == 11 AAAA $ ./a.out 80 n+1 == 81 too long! $ python Python 2.7.6 (default, Jun 22 2015, 17:58:13) [GCC 4.8.2] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> (1<<32)-1 4294967295 >>> $ ./a.out 4294967295 n+1 == 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA *** stack smashing detected ***: ./a.out terminated Aborted (core dumped)
これを防ぐには、入力に依存しない箇所で計算を行うようにすればよい。
--- integer_overflow.c 2016-09-27 15:23:56.920312000 +0900 +++ patched/integer_overflow.c 2016-09-27 15:24:30.728312000 +0900 @@ -9,7 +9,7 @@ scanf("%d", &n); printf("n+1 == %d\n", n+1); - if (n+1 > sizeof(buf)) { + if (n > sizeof(buf)-1) { puts("too long!"); exit(1); }
符号エラー(Signedness Error)
符号エラーは、符号付き整数が符号なし整数として扱われる、あるいはその逆が起こることにより発生するバグである。
/* signedness_error.c */ #include <stdio.h> #include <stdlib.h> int main() { char buf[40]; int n; scanf("%d", &n); if (n > 40) { puts("too long!"); exit(1); } read(0, buf, n); return 0; }
上のコードではバッファサイズのチェックが行われているが、次のように-1を与えたときチェックを通過してしまう。
$ gcc signedness_error.c $ ./a.out 10 AAAA $ ./a.out 80 too long! $ ./a.out -1 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA *** stack smashing detected ***: ./a.out terminated Aborted (core dumped) $ strace ./a.out execve("./a.out", ["./a.out"], [/* 21 vars */]) = 0 brk(0) = 0x1178000 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f5d72941000 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 fstat(3, {st_mode=S_IFREG|0644, st_size=37010, ...}) = 0 mmap(NULL, 37010, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f5d72937000 close(3) = 0 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3 read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P \2\0\0\0\0\0"..., 832) = 832 fstat(3, {st_mode=S_IFREG|0755, st_size=1840928, ...}) = 0 mmap(NULL, 3949248, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f5d7235c000 mprotect(0x7f5d72516000, 2097152, PROT_NONE) = 0 mmap(0x7f5d72716000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1ba000) = 0x7f5d72716000 mmap(0x7f5d7271c000, 17088, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f5d7271c000 close(3) = 0 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f5d72936000 mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f5d72934000 arch_prctl(ARCH_SET_FS, 0x7f5d72934740) = 0 mprotect(0x7f5d72716000, 16384, PROT_READ) = 0 mprotect(0x600000, 4096, PROT_READ) = 0 mprotect(0x7f5d72943000, 4096, PROT_READ) = 0 munmap(0x7f5d72937000, 37010) = 0 fstat(0, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f5d72940000 read(0, -1 "-1\n", 1024) = 3 read(0, AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"..., 4294967295) = 49 open("/dev/tty", O_RDWR|O_NOCTTY|O_NONBLOCK) = 3 writev(3, [{"*** ", 4}, {"stack smashing detected", 23}, {" ***: ", 6}, {"./a.out", 7}, {" terminated\n", 12}], 5*** stack smashing detected ***: ./a.out terminated ) = 52 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f5d7293f000 rt_sigprocmask(SIG_UNBLOCK, [ABRT], NULL, 8) = 0 gettid() = 4558 tgkill(4558, 4558, SIGABRT) = 0 --- SIGABRT {si_signo=SIGABRT, si_code=SI_TKILL, si_pid=4558, si_uid=1000} --- +++ killed by SIGABRT (core dumped) +++ Aborted (core dumped)
straceコマンドの結果から、チェックを通過した-1がread関数では符号なし整数4294967295として扱われていることがわかる。
これを防ぐには、最初から符号なし整数として宣言すればよい。
--- signedness_error.c 2016-09-27 15:50:22.524312000 +0900 +++ patched/signedness_error.c 2016-09-27 15:50:51.888312000 +0900 @@ -5,7 +5,7 @@ int main() { char buf[40]; - int n; + unsigned int n; scanf("%d", &n); if (n > 40) {
関連リンク
「HTTPプロクシライブラリproxy2の設計と実装」というタイトルで発表した
Pari/GPでECDH鍵交換、ECDSA署名をやってみる
TLS 1.2では、楕円曲線暗号であるECDH鍵交換、ECDSA署名を使うことができる。 ここでは、数式処理システムPari/GPを使ってこれらの計算をやってみる。
環境
Ubuntu 14.04.4 LTS 64bit版、Pari/GP 2.5.5
$ uname -a Linux vm-ubuntu64 3.19.0-25-generic #26~14.04.1-Ubuntu SMP Fri Jul 24 21:16:20 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux $ lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 14.04.4 LTS Release: 14.04 Codename: trusty $ gp --version-short 2.5.5
ECDH、ECDSAが使われている通信を見てみる
一例として、GoogleへのTLS通信では現時点でECDH、ECDSAが使われている。 実際に通信をWiresharkで確認した結果を次に示す。
Frame 31: 1294 bytes on wire (10352 bits), 1294 bytes captured (10352 bits) on interface 0 (snip) Secure Sockets Layer TLSv1.2 Record Layer: Handshake Protocol: Server Hello Content Type: Handshake (22) Version: TLS 1.2 (0x0303) Length: 76 Handshake Protocol: Server Hello Handshake Type: Server Hello (2) Length: 72 Version: TLS 1.2 (0x0303) Random Session ID Length: 0 Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (0xc02b) Compression Method: null (0) Extensions Length: 32 Extension: renegotiation_info Extension: server_name Extension: Extended Master Secret Extension: SessionTicket TLS Extension: Application Layer Protocol Negotiation Extension: ec_point_formats Frame 35: 401 bytes on wire (3208 bits), 401 bytes captured (3208 bits) on interface 0 (snip) Secure Sockets Layer TLSv1.2 Record Layer: Handshake Protocol: Certificate Content Type: Handshake (22) Version: TLS 1.2 (0x0303) Length: 3739 Handshake Protocol: Certificate Handshake Type: Certificate (11) Length: 3735 Certificates Length: 3732 Certificates (3732 bytes) Certificate Length: 1814 Certificate: 30820712308205faa00302010202082e7dfcf07569326730... (id-at-commonName=*.google.com,id-at-organizationName=Google Inc,id-at-localityName=Mountain View,id-at-stateOrProvinceName=California,id-at-countryName=US) signedCertificate version: v3 (2) serialNumber: 3350111807525696103 signature (sha256WithRSAEncryption) issuer: rdnSequence (0) validity subject: rdnSequence (0) subjectPublicKeyInfo algorithm (id-ecPublicKey) Algorithm Id: 1.2.840.10045.2.1 (id-ecPublicKey) ECParameters: namedCurve (0) namedCurve: 1.2.840.10045.3.1.7 (secp256r1) Padding: 0 subjectPublicKey: 041094b0ae65b5baa7e408de4694ca8fcb7275db3a2c3722... extensions: 9 items algorithmIdentifier (sha256WithRSAEncryption) Padding: 0 encrypted: 35bb7787aa57a4981d93b867e05e1e04c7030d051803f818... Certificate Length: 1012 Certificate: 308203f0308202d8a0030201020203023a92300d06092a86... (id-at-commonName=Google Internet Authority G2,id-at-organizationName=Google Inc,id-at-countryName=US) Certificate Length: 897 Certificate: 3082037d308202e6a003020102020312bbe6300d06092a86... (id-at-commonName=GeoTrust Global CA,id-at-organizationName=GeoTrust Inc.,id-at-countryName=US) Secure Sockets Layer TLSv1.2 Record Layer: Handshake Protocol: Server Key Exchange Content Type: Handshake (22) Version: TLS 1.2 (0x0303) Length: 148 Handshake Protocol: Server Key Exchange Handshake Type: Server Key Exchange (12) Length: 144 EC Diffie-Hellman Server Params Curve Type: named_curve (0x03) Named Curve: secp256r1 (0x0017) Pubkey Length: 65 Pubkey: 0480168e3311d4762dad286445c3bafd6f884e14720c882f... Signature Hash Algorithm: 0x0603 Signature Hash Algorithm Hash: SHA512 (6) Signature Hash Algorithm Signature: ECDSA (3) Signature Length: 71 Signature: 3045022100f0e6e6cfe84c316f6a3b0a66e7250c4610f3e8... TLSv1.2 Record Layer: Handshake Protocol: Server Hello Done Frame 47: 200 bytes on wire (1600 bits), 200 bytes captured (1600 bits) on interface 0 (snip) Secure Sockets Layer TLSv1.2 Record Layer: Handshake Protocol: Client Key Exchange Content Type: Handshake (22) Version: TLS 1.2 (0x0303) Length: 70 Handshake Protocol: Client Key Exchange Handshake Type: Client Key Exchange (16) Length: 66 EC Diffie-Hellman Client Params Pubkey Length: 65 Pubkey: 0450324b47117a7e0b967e798b9ce8e4147439e403d36191... TLSv1.2 Record Layer: Change Cipher Spec Protocol: Change Cipher Spec TLSv1.2 Record Layer: Handshake Protocol: Multiple Handshake Messages
上の結果から、CipherSuiteとしてTLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
が選ばれていることがわかる。
そして、サーバ証明書には楕円曲線パラメータsecp256r1でのECDSA用公開鍵が記されており、secp256r1でのECDH用公開鍵がECDSAで署名されていることがわかる。
なお、RFC 4492ではECDHE_ECDSAを用いる場合、サーバ証明書もECDSAで署名されていなければならない(MUST)と記されているが、上の結果ではRSAで署名されているようである。
Pari/GPのインストール
楕円曲線暗号は、ざっくり言うと、素数pを法とする楕円曲線上で定義された定数倍の逆演算が計算量的に困難であること(楕円曲線上の離散対数問題)をもとにした暗号の総称である。 すなわち、ある点Pをd倍した点Qは計算できるが、定数dと点Qから点Pを逆算することが困難であるという性質をもとにしたものである。 RSA暗号において有限体上でe乗した値の逆算が困難であること(離散対数問題)を、楕円曲線上での演算に置き換えたものと考えてもよい。 楕円曲線上で定義された演算の詳細については、Wikipedia等を参照されたい。
楕円曲線上での演算を行うために、ここでは数式処理システムPari/GPを用いることにする。 Pari/GPは次のようにしてインストールできる。
$ sudo apt-get install pari-gp
ECDH鍵交換をやってみる
ECDH鍵交換は、有限体上でのDiffee-Hellman鍵交換を楕円曲線上の演算に置き換えたものである。 Wikipediaを参考に、楕円曲線パラメータsecp256r1で定義される楕円曲線上でのECDH鍵交換を計算してみると次のようになる。
\\ http://pari.math.u-bordeaux.fr/faq.html#hexa hextodec(s) = { my(v=Vec(s), a=10,b=11,c=12,d=13,e=14,f=15, A=10,B=11,C=12,D=13,E=14,F=15, h); for(i=1,#v,h = (h<<4) + eval(v[i])); h; } \\ secp256r1 parameters \\ http://www.secg.org/sec1-v2.pdf \\ http://www.secg.org/sec2-v2.pdf p = hextodec("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF") a = hextodec("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC") b = hextodec("5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B") Gx = hextodec("6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296") Gy = hextodec("4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5") G = [Gx, Gy] n = hextodec("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551") \\ secp256r1 curve E = ellinit([0, 0, 0, a, b] * Mod(1, p)) \\ secret key da = random(n) db = random(n) \\ public key Qa = ellpow(E, G, da) Qb = ellpow(E, G, db) \\ calculate shared secret Xa = lift(ellpow(E, Qb, da))[1] Xb = lift(ellpow(E, Qa, db))[1] Xa == Xb
上のコードでは、AとBが互いの公開鍵Qa、Qbを交換し、それぞれの秘密鍵と掛け合わせることで共通鍵Xa == Xbを計算している。
ここで、lift関数はMod(a,b) => a
を求める関数である。
実際に実行すると、次のようになる。
$ gp -q ? \\ http://pari.math.u-bordeaux.fr/faq.html#hexa ? hextodec(s) = { my(v=Vec(s), a=10,b=11,c=12,d=13,e=14,f=15, A=10,B=11,C=12,D=13,E=14,F=15, h); for(i=1,#v,h = (h<<4) + eval(v[i])); h; } ? ? \\ secp256r1 parameters ? \\ http://www.secg.org/sec1-v2.pdf ? \\ http://www.secg.org/sec2-v2.pdf ? p = hextodec("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF") 115792089210356248762697446949407573530086143415290314195533631308867097853951 ? a = hextodec("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC") 115792089210356248762697446949407573530086143415290314195533631308867097853948 ? b = hextodec("5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B") 41058363725152142129326129780047268409114441015993725554835256314039467401291 ? Gx = hextodec("6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296") 48439561293906451759052585252797914202762949526041747995844080717082404635286 ? Gy = hextodec("4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5") 36134250956749795798585127919587881956611106672985015071877198253568414405109 ? G = [Gx, Gy] [48439561293906451759052585252797914202762949526041747995844080717082404635286, 36134250956749795798585127919587881956611106672985015071877198253568414405109] ? n = hextodec("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551") 115792089210356248762697446949407573529996955224135760342422259061068512044369 ? ? \\ secp256r1 curve ? E = ellinit([0, 0, 0, a, b] * Mod(1, p)) [Mod(0, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(0, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(0, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(115792089210356248762697446949407573530086143415290314195533631308867097853948, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(41058363725152142129326129780047268409114441015993725554835256314039467401291, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(0, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(115792089210356248762697446949407573530086143415290314195533631308867097853945, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(48441365690252319754607072170781500106371620648684588023807393947290771751213, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(115792089210356248762697446949407573530086143415290314195533631308867097853942, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(144, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(73745129047917570410340083507285168261568990675547578651163356492099206447533, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(47064476442213300654454205837611899485069387829947879813735601543372794627813, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(7958909377132088453074743217357398615041065282494610304372115906626967530147, 115792089210356248762697446949407573530086143415290314195533631308867097853951), 0, 0, 0, 0, 0, 0] ? \\ secret key ? da = random(n) 41624337018869194729192205381537838788846303834619688597471765238035829032504 ? db = random(n) 112889434785065900135211481371037383646282385554418514861667765615237067913479 ? \\ public key ? Qa = ellpow(E, G, da) [Mod(66427298351632458827230541581873808673432665230371912577791853634759425959558, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(1206785862317786198788010821239105192836149114902459754806002568469592604088, 115792089210356248762697446949407573530086143415290314195533631308867097853951)] ? Qb = ellpow(E, G, db) [Mod(45117477251749228939119226983445827678526666004268395927426481263854185200718, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(40767119766631682297642348857294685404708822382670655743751860183794421610264, 115792089210356248762697446949407573530086143415290314195533631308867097853951)] ? ? \\ calculate shared secret ? Xa = lift(ellpow(E, Qb, da))[1] 55382482432028264043275192986018530076536941443548819581226267882802812179275 ? Xb = lift(ellpow(E, Qa, db))[1] 55382482432028264043275192986018530076536941443548819581226267882802812179275 ? Xa == Xb 1
XaとXbが同じ値となり、共通鍵を共有できていることが確認できる。
ECDSA署名をやってみる
ECDSA署名は、有限体上でのDSA署名を楕円曲線上の演算に置き換えたものである。 Wikipediaを参考に、楕円曲線パラメータsecp256r1で定義される楕円曲線上でのECDSA署名を計算してみると次のようになる。
\\ http://pari.math.u-bordeaux.fr/faq.html#hexa hextodec(s) = { my(v=Vec(s), a=10,b=11,c=12,d=13,e=14,f=15, A=10,B=11,C=12,D=13,E=14,F=15, h); for(i=1,#v,h = (h<<4) + eval(v[i])); h; } \\ secp256r1 parameters \\ http://www.secg.org/sec1-v2.pdf \\ http://www.secg.org/sec2-v2.pdf p = hextodec("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF") a = hextodec("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC") b = hextodec("5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B") Gx = hextodec("6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296") Gy = hextodec("4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5") G = [Gx, Gy] n = hextodec("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551") \\ secp256r1 curve E = ellinit([0, 0, 0, a, b] * Mod(1, p)) \\ secret key d = random(n) \\ public key Q = ellpow(E, G, d) \\ SHA-512 hash value z = hextodec("cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e") z = z >> 256 \\ leftmost 256 bits \\ sign k = random(n) X = lift(ellpow(E, G, k)) r = Mod(X[1], n) s = Mod((z + r * d)/k, n) S = lift([r, s]) \\ signature \\ verify r = S[1] s = S[2] w = Mod(1, n)/s u1 = lift(z * w) u2 = lift(r * w) X = elladd(E, ellpow(E, G, u1), ellpow(E, Q, u2)) r == lift(X[1]) \\ verification result
上のコードでは、秘密鍵dと公開鍵Qの組を用いて、dでSHA-512ハッシュ値zに対する署名Sを生成した後、zとQでこの署名Sの検証を行っている。 ここで、SHA-512ハッシュ値は512bitであるが、署名を計算する際には上位256bit(楕円曲線パラメータのnのbit数)が取り出されて用いられる。
実際に実行すると、次のようになる。
$ gp -q ? \\ http://pari.math.u-bordeaux.fr/faq.html#hexa ? hextodec(s) = { my(v=Vec(s), a=10,b=11,c=12,d=13,e=14,f=15, A=10,B=11,C=12,D=13,E=14,F=15, h); for(i=1,#v,h = (h<<4) + eval(v[i])); h; } ? ? \\ secp256r1 parameters ? \\ http://www.secg.org/sec1-v2.pdf ? \\ http://www.secg.org/sec2-v2.pdf ? p = hextodec("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF") 115792089210356248762697446949407573530086143415290314195533631308867097853951 ? a = hextodec("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC") 115792089210356248762697446949407573530086143415290314195533631308867097853948 ? b = hextodec("5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B") 41058363725152142129326129780047268409114441015993725554835256314039467401291 ? Gx = hextodec("6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296") 48439561293906451759052585252797914202762949526041747995844080717082404635286 ? Gy = hextodec("4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5") 36134250956749795798585127919587881956611106672985015071877198253568414405109 ? G = [Gx, Gy] [48439561293906451759052585252797914202762949526041747995844080717082404635286, 36134250956749795798585127919587881956611106672985015071877198253568414405109] ? n = hextodec("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551") 115792089210356248762697446949407573529996955224135760342422259061068512044369 ? ? \\ secp256r1 curve ? E = ellinit([0, 0, 0, a, b] * Mod(1, p)) [Mod(0, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(0, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(0, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(115792089210356248762697446949407573530086143415290314195533631308867097853948, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(41058363725152142129326129780047268409114441015993725554835256314039467401291, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(0, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(115792089210356248762697446949407573530086143415290314195533631308867097853945, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(48441365690252319754607072170781500106371620648684588023807393947290771751213, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(115792089210356248762697446949407573530086143415290314195533631308867097853942, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(144, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(73745129047917570410340083507285168261568990675547578651163356492099206447533, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(47064476442213300654454205837611899485069387829947879813735601543372794627813, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(7958909377132088453074743217357398615041065282494610304372115906626967530147, 115792089210356248762697446949407573530086143415290314195533631308867097853951), 0, 0, 0, 0, 0, 0] ? \\ secret key ? d = random(n) 41624337018869194729192205381537838788846303834619688597471765238035829032504 ? \\ public key ? Q = ellpow(E, G, d) [Mod(66427298351632458827230541581873808673432665230371912577791853634759425959558, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(1206785862317786198788010821239105192836149114902459754806002568469592604088, 115792089210356248762697446949407573530086143415290314195533631308867097853951)] ? ? \\ SHA-512 hash value ? z = hextodec("cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e") 10868450558671247443152026947160338505683745266658651051718065983487878962987857602829315249215796444208488632888003673539585986066311769564391053988452926 ? z = z >> 256 \\ leftmost 256 bits 93861770957395276492717477787726143810336548400896766194917568669650606942670 ? ? \\ sign ? k = random(n) 112889434785065900135211481371037383646282385554418514861667765615237067913479 ? X = lift(ellpow(E, G, k)) [45117477251749228939119226983445827678526666004268395927426481263854185200718, 40767119766631682297642348857294685404708822382670655743751860183794421610264] ? r = Mod(X[1], n) Mod(45117477251749228939119226983445827678526666004268395927426481263854185200718, 115792089210356248762697446949407573529996955224135760342422259061068512044369) ? s = Mod((z + r * d)/k, n) Mod(19480684571390165669037418791352587666543987715102909683921619662453630129808, 115792089210356248762697446949407573529996955224135760342422259061068512044369) ? S = lift([r, s]) \\ signature [45117477251749228939119226983445827678526666004268395927426481263854185200718, 19480684571390165669037418791352587666543987715102909683921619662453630129808] ? ? \\ verify ? r = S[1] 45117477251749228939119226983445827678526666004268395927426481263854185200718 ? s = S[2] 19480684571390165669037418791352587666543987715102909683921619662453630129808 ? w = Mod(1, n)/s Mod(45806731425320108599593801776916401592588010577151454492237521859734605583062, 115792089210356248762697446949407573529996955224135760342422259061068512044369) ? u1 = lift(z * w) 2526355770588513432897987911358560530387299975513306266181348358497798666960 ? u2 = lift(r * w) 39403108001448584892010322851840404729316330706803748468373485665520707319225 ? X = elladd(E, ellpow(E, G, u1), ellpow(E, Q, u2)) [Mod(45117477251749228939119226983445827678526666004268395927426481263854185200718, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(40767119766631682297642348857294685404708822382670655743751860183794421610264, 115792089210356248762697446949407573530086143415290314195533631308867097853951)] ? r == lift(X[1]) \\ verification result 1
上の結果から、秘密鍵dで計算されたハッシュ値zに対する署名Sを、zと公開鍵Qで検証できていることが確認できる。
関連リンク
vim-tinyで矩形挿入・削除する方法のメモ
555タイマーICと圧電スピーカーでアナログシンセもどきを作ってみる
555タイマーIC(集積回路)を発振回路として使うと、さまざまな周波数の矩形波を作ることができる。 また、圧電スピーカーを使うと、一定の周波数で電圧を変化させることにより音を出すことができる。 ここでは、これらと半固定抵抗を組み合わせ、単純な回路によるアナログシンセサイザーもどきを作ってみる。
部品調達
- 長いブレッドボード(参考)
- ジャンパワイヤ(参考)
- 006P型9V電池および電池ケース(参考)
- 圧電スピーカー SPT08 x1(参考)
- タイマーIC NE555P x2(参考)
- 汎用オペアンプ LM358N x1(参考)
- つまみ付き半固定ボリューム 20kΩ x2、50kΩ x2、100kΩ x1(参考)
- アルミ電解コンデンサ 10uF x2(参考)
- 積層セラミックコンデンサ 0.01uF x1、0.1uF x3(参考)
- 1/4Wカーボン抵抗 220Ω x1、470Ω x2、1kΩ x5(参考)
- タクトスイッチ x1(参考)
- 5mm高輝度LED x1(参考)
アナログシンセサイザーの仕組み
シンセサイザーには、大きく分けてアナログ回路を用いるアナログシンセサイザーと、デジタル信号処理を用いるデジタルシンセサイザーがある。 また、音を合成する方法にも、基本波形に周波数フィルタをかける減算合成、複数の基本波形を重ねる加算合成、周波数変調(FM)等の変調方式をもとにした変調合成などがある(参考)。
減算合成によるアナログシンセサイザーの仕組みについては、次のサイトがわかりやすい。
(上記サイトより引用)
上の図におけるそれぞれの回路の役割を簡単にまとめると次のようになる。
- VCO (Voltage-controlled Oscillator)
- 正弦波や矩形波などの基本波形を作る。音色、音程に相当
- VCF(Voltage-controlled Filter)
- ローパスフィルタやハイパスフィルタなどの周波数フィルタをかける。音のゆがみに相当
- VCA(Voltage-controlled Amplifier)
- 波の振幅を変化させる。音量に相当
- LFO(Low-frequency Oscillator)
- EG(Envelope Generator)
- キーボードを押した後の音の変化を再現する
一般的なアナログシンセはさまざまな基本波形やフィルタを備えているが、ここではできるだけ単純な回路となるように、
- VCOは555タイマーICによる矩形波のみ
- VCFは一次RCローパスフィルタ、一次RCハイパスフィルタの組み合わせ
- VCAはオペアンプ反転増幅回路
- LFOは555タイマーICによる矩形波に一次RCローパスフィルタ
- EG、キーボードなし
のアナログシンセもどきを作ってみることにする。
基本回路図
555タイマーICによる発振回路は次で表される。
OUTからは矩形波が表れ、その発振周波数は 1/(ln(2)*C*(R1+2*R2))
、デューティー比は (R1+R2)/(R1+2*R2)
である。
1次RCローパスフィルタ、一次RCハイパスフィルタは次で表わされる。
ローパスフィルタはカットオフ周波数を越える周波数成分を弱める働きをする。
一方、ハイパスフィルタはカットオフ周波数を下回る周波数成分を弱める働きをする。
カットオフ周波数はどちらの場合も 1/(2*pi*R*C)
である。
オペアンプ反転増幅回路は次で表される。
マイナスの電圧の -R2/R1
倍が出力電圧として表れる。
また、R3はプラス側とマイナス側に流れる電流の差(バイアス電流)を打ち消すためのものであり、その抵抗値はR1とR2の並列抵抗の値となる。
なお、オペアンプ非反転増幅回路は1未満の増幅率にできないため、今回の例には適さない。
全体回路図
上の回路では、半固定抵抗でそれぞれの電圧調整を行う。 また、タクトスイッチでLFOのオンオフを切り替え、これに合わせてLEDが光るようになっている。
上の回路において、LFOのOUT(3番ピン)はローパスフィルタを通してVCOのCTRL(5番ピン)に繋がっており、パルス位置変調により発振周波数を揺らす働きをする。 また、タクトスイッチはLFOのVccに繋がっており、オンにすることでLFOが発振する。
発振回路の周波数やRCフィルタのカットオフ周波数は以下のページで計算できる。
上の回路において、半固定抵抗による変域の理論値は次のようになる。
- VCO: 140.8Hz~5842Hz
- VCF LPF: 79.58Hz~無限大
- VCF HPF: 79.58Hz~無限大
- VCA: 0~100倍
- LFO: 1.408Hz~58.42Hz
- LFO LPF: 15.92Hz
実際にブレッドボード上に作った回路の写真を次に示す。
鳴らしてみる
9V電池を繋いで鳴らしてみると、次の動画のようになる。
半固定抵抗およびタクトスイッチの操作により、それぞれ期待する効果が得られていることが確認できる。
関連リンク
Raspberry Pi 3でパケットキャプチャ用無線アクセスポイントを作る
Raspberry Pi 3にはWi-Fiモジュール(Broadcom BCM43438)が搭載されているが、このモジュールはクライアントとしてだけではなく、アクセスポイントとして動作させることもできる。 ここでは、Raspberry Pi 3でDHCPサーバ付き無線ルータを作り、アクセスポイントに接続するだけで簡単にパケットキャプチャできるようにしてみる。
環境
Raspberry Pi 3 Model B (Raspbian Jessie Lite)
$ uname -a Linux raspberrypi 4.4.9-v7+ #884 SMP Fri May 6 17:28:59 BST 2016 armv7l GNU/Linux $ cat /etc/os-release PRETTY_NAME="Raspbian GNU/Linux 8 (jessie)" NAME="Raspbian GNU/Linux" VERSION_ID="8" VERSION="8 (jessie)" ID=raspbian ID_LIKE=debian HOME_URL="http://www.raspbian.org/" SUPPORT_URL="http://www.raspbian.org/RaspbianForums" BUG_REPORT_URL="http://www.raspbian.org/RaspbianBugs"
無線インタフェースが対応している動作モードの確認
次のコマンドで、無線インタフェースが対応している動作モードを調べることができる。
$ iw list Wiphy phy0 (snip) Supported interface modes: * IBSS * managed * AP * P2P-client * P2P-GO * P2P-device (snip)
上の結果より、クライアントとして動作するmanagedモードに加え、アクセスポイントとして動作するAPモードをサポートしていることがわかる。
無線インタフェースのIP設定
以降、上流の有線ネットワークを192.168.0.0/24、作成する無線ネットワークを192.168.1.0/24とする。 また、IPv6についてはUnique Local IPv6 Unicast Address(ULA)を用い、IPv4同様別セグメントを作ることにする。 ここでは、そのセグメントをfdXX:XXXX:XXXX:1::/64で表し、Xの部分にはランダムに生成した値が入るものとする(参考)。
まず、無線インタフェースwlan0のIPアドレスを192.168.1.1およびfdXX:XXXX:XXXX:1::1に設定する。
$ sudo vi /etc/network/interfaces allow-hotplug wlan0 iface wlan0 inet static address 192.168.1.1 netmask 255.255.255.0 iface wlan0 inet6 static address fdXX:XXXX:XXXX:1::1 netmask 64 #iface wlan0 inet manual # wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf
hostapdの設定
次に、hostapdをインストールし、無線アクセスポイントの設定を行う。
$ sudo apt-get install hostapd
$ sudo sh -c "zcat /usr/share/doc/hostapd/examples/hostapd.conf.gz > /etc/hostapd/hostapd.conf"
$ sudo vi /etc/hostapd/hostapd.conf interface=wlan0 ssid=raspberrypi_nomap wpa=2 wpa_passphrase=SECRETPASSPHRASE wpa_key_mgmt=WPA-PSK rsn_pairwise=CCMP
一時的にhostapdを起動し、他の端末から設定したSSIDが見えていることを確認する。
$ sudo hostapd /etc/hostapd/hostapd.conf
SSIDが確認できたら、OS起動時にhostapdが自動起動するように設定する。
$ sudo vi /etc/default/hostapd DAEMON_CONF="/etc/hostapd/hostapd.conf"
dnsmasqの設定
無線ネットワークにおけるDHCP/DNSサーバとして、dnsmasqをインストールする。
$ sudo apt-get install dnsmasq
続けて、設定ファイルを編集する。
$ sudo vi /etc/dnsmasq.conf no-resolv no-poll interface=wlan0 enable-ra dhcp-range=192.168.1.101,192.168.1.200 dhcp-range=::,constructor:wlan0,ra-stateless server=192.168.0.1
上の設定は、wlan0インタフェースにDHCPv4で192.168.1.101-200を配り、IPv6ではDHCPv6サーバを使用したステートレス自動設定を行う。 また、dnsmasqが参照するDNSサーバについては/etc/resolv.confを参照せず、有線ネットワーク側のDNSサーバ(192.168.0.1)を直接指定している。
パケット転送およびNAPTの設定
IPv4、IPv6のそれぞれについてパケット転送を行うように設定する。
$ sudo vi /etc/sysctl.conf net.ipv4.conf.all.forwarding = 1 net.ipv6.conf.all.forwarding = 1
次に、iptables-persistentをインストールし、無線ネットワークからeth0に転送されるパケットについてNAPT(IPマスカレード)を行うように設定する。
$ sudo apt-get install iptables-persistent
$ sudo vi /etc/iptables/rules.v4 # Generated by iptables-save v1.4.21 on Thu Sep 1 23:52:33 2016 *nat :PREROUTING ACCEPT [0:0] :INPUT ACCEPT [0:0] :OUTPUT ACCEPT [0:0] :POSTROUTING ACCEPT [0:0] -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j MASQUERADE COMMIT # Completed on Thu Sep 1 23:52:33 2016 # Generated by iptables-save v1.4.21 on Thu Sep 1 23:52:33 2016 *filter :INPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] COMMIT # Completed on Thu Sep 1 23:52:33 2016 $ sudo vi /etc/iptables/rules.v6 # Generated by ip6tables-save v1.4.21 on Mon Sep 5 01:44:20 2016 *nat :PREROUTING ACCEPT [0:0] :INPUT ACCEPT [0:0] :OUTPUT ACCEPT [0:0] :POSTROUTING ACCEPT [0:0] -A POSTROUTING -s fdXX:XXXX:XXXX:1::/64 -o eth0 -j MASQUERADE COMMIT # Completed on Mon Sep 5 01:44:20 2016 # Generated by ip6tables-save v1.4.21 on Wed May 25 21:30:37 2016 *filter :INPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] COMMIT # Completed on Wed May 25 21:30:37 2016
なお、「Raspberry PiでIPv6 PPPoE対応ルータを作る」で説明した方法でRaspberry PiをPPPoEルータにしている場合は、IPv6のNAPTインタフェースをeth0からppp0に変える必要がある。
最後にRaspberry Piを再起動し、wlan0に指定したIPアドレスが割り当てられていること、hostapd/dnsmasqが起動していることを確認する。
$ sudo reboot
$ ip addr (snip) 3: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 link/ether b8:27:eb:XX:XX:XX brd ff:ff:ff:ff:ff:ff inet 192.168.1.1/24 brd 192.168.1.255 scope global wlan0 valid_lft forever preferred_lft forever inet 169.254.120.61/16 brd 169.254.255.255 scope global wlan0 valid_lft forever preferred_lft forever inet6 fdXX:XXXX:XXXX:1::1/64 scope global valid_lft forever preferred_lft forever (snip) $ systemctl status hostapd ● hostapd.service - LSB: Advanced IEEE 802.11 management daemon Loaded: loaded (/etc/init.d/hostapd) Active: active (running) since Mon 2016-09-05 03:18:44 JST; 4min 45s ago Process: 1319 ExecStart=/etc/init.d/hostapd start (code=exited, status=0/SUCCESS) CGroup: /system.slice/hostapd.service └─1534 /usr/sbin/hostapd -B -P /run/hostapd.pid /etc/hostapd/hostapd.conf $ systemctl status dnsmasq ● dnsmasq.service - dnsmasq - A lightweight DHCP and caching DNS server Loaded: loaded (/lib/systemd/system/dnsmasq.service; enabled) Drop-In: /run/systemd/generator/dnsmasq.service.d └─50-dnsmasq-$named.conf, 50-insserv.conf-$named.conf Active: active (running) since Mon 2016-09-05 03:18:07 JST; 5min ago Process: 712 ExecStartPost=/etc/init.d/dnsmasq systemd-start-resolvconf (code=exited, status=0/SUCCESS) Process: 642 ExecStart=/etc/init.d/dnsmasq systemd-exec (code=exited, status=0/SUCCESS) Process: 553 ExecStartPre=/usr/sbin/dnsmasq --test (code=exited, status=0/SUCCESS) Main PID: 711 (dnsmasq) CGroup: /system.slice/dnsmasq.service └─711 /usr/sbin/dnsmasq -x /var/run/dnsmasq/dnsmasq.pid -u dnsmasq -r /var/run/dnsmasq/resolv.conf -7 /etc/dnsmasq.d,.dpkg-dist,.dpkg-old,.dpkg-new --local-service --trust-anchor=.,19...
無線アクセスポイントを通る通信をパケットキャプチャしてみる
パケットキャプチャを行うために、tcpdumpをインストールする。
$ sudo apt-get install tcpdump
wlan0インタフェースに対してtcpdumpを実行し、Android端末から無線アクセスポイントに接続してみる。
$ sudo tcpdump -i wlan0 -n tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on wlan0, link-type EN10MB (Ethernet), capture size 262144 bytes 03:34:55.912458 ba:27:eb:XX:XX:XX > b8:27:eb:XX:XX:XX, ethertype Unknown (0x886c), length 74: 0x0000: 8001 0068 0000 1018 0001 0002 0000 0000 ...h............ 0x0010: 0004 0000 0000 0000 0000 0000 0000 0000 ................ 0x0020: 0000 90b6 86c3 2241 776c 3000 0000 0000 ......"Awl0..... 0x0030: 0000 0000 0000 0000 0000 0000 ............ 03:34:55.924089 90:b6:86:XX:XX:XX > ff:ff:ff:ff:ff:ff Null Unnumbered, xid, Flags [Response], length 6: 01 00 03:34:55.925734 ba:27:eb:XX:XX:XX > b8:27:eb:XX:XX:XX, ethertype Unknown (0x886c), length 229: 0x0000: 8001 0103 0000 1018 0001 0002 0000 0000 ................ 0x0010: 0008 0000 0000 0000 0000 0000 0000 0000 ................ 0x0020: 009b 90b6 86c3 2241 776c 3000 0000 0000 ......"Awl0..... 0x0030: 0000 0000 0000 0000 0000 0011 7261 7370 ............rasp 0x0040: 6265 7272 7970 695f 6e6f 6d61 7001 0882 berrypi_nomap... 0x0050: 848b 9624 3048 6c32 040c 1218 6021 0202 ...$0Hl2....`!.. 0x0060: 1224 0201 0d30 1401 0000 0fac 0401 0000 .$...0.......... 0x0070: 0fac 0401 0000 0fac 0280 002d 1a2d 0017 ...........-.-.. 0x0080: ff00 0000 0000 0000 0000 0000 0000 0000 ................ 0x0090: 0000 0000 0000 007f 0800 0008 8001 4000 ..............@. 0x00a0: 40dd 1e00 904c 332d 0017 ff00 0000 0000 @....L3-........ 0x00b0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 0x00c0: 00dd 0900 1018 0200 0010 0000 dd07 0050 ...............P 0x00d0: f202 0001 0000 00 ....... 03:34:55.930534 EAPOL key (3) v2, len 95 03:34:55.970042 EAPOL key (3) v1, len 117 03:34:55.971198 EAPOL key (3) v2, len 151 03:34:55.983969 EAPOL key (3) v1, len 95 03:34:56.051210 IP6 :: > ff02::1:XXXX:XXXX: ICMP6, neighbor solicitation, who has fe80::XXXX:XXXX:XXXX:XXXX, length 24 03:34:56.056070 IP6 :: > ff02::16: HBH ICMP6, multicast listener report v2, 1 group record(s), length 28 03:34:56.412020 IP6 fe80::XXXX:XXXX:XXXX:XXXX > ff02::2: ICMP6, router solicitation, length 16 03:34:56.412693 IP6 fe80::XXXX:XXXX:XXXX:XXXX > fe80::XXXX:XXXX:XXXX:XXXX: ICMP6, router advertisement, length 64 03:34:56.426102 IP6 :: > ff02::1:XXXX:XXXX: ICMP6, neighbor solicitation, who has fdXX:XXXX:XXXX:1:XXXX:XXXX:XXXX:XXXX, length 24 03:34:56.437585 IP6 :: > ff02::1:XXXX:XXXX: ICMP6, neighbor solicitation, who has fdXX:XXXX:XXXX:1:XXXX:XXXX:XXXX:XXXX, length 24 03:34:56.437758 IP6 :: > ff02::16: HBH ICMP6, multicast listener report v2, 2 group record(s), length 48 03:34:56.462079 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from 90:b6:86:c3:22:41, length 314 03:34:56.622910 IP 192.168.1.1.67 > 192.168.1.170.68: BOOTP/DHCP, Reply, length 300 03:34:56.719521 ARP, Request who-has 192.168.1.1 tell 192.168.1.170, length 28 03:34:56.719557 ARP, Reply 192.168.1.1 is-at b8:27:eb:XX:XX:XX, length 28 03:34:57.049105 IP6 fe80::XXXX:XXXX:XXXX:XXXX > ff02::2: ICMP6, router solicitation, length 16 03:34:57.049738 IP6 fe80::XXXX:XXXX:XXXX:XXXX > fe80::XXXX:XXXX:XXXX:XXXX: ICMP6, router advertisement, length 64 03:34:59.664530 IP6 fe80::XXXX:XXXX:XXXX:XXXX > ff02::16: HBH ICMP6, multicast listener report v2, 1 group record(s), length 28 03:35:01.419914 IP6 fe80::XXXX:XXXX:XXXX:XXXX > fe80::XXXX:XXXX:XXXX:XXXX: ICMP6, neighbor solicitation, who has fe80::XXXX:XXXX:XXXX:XXXX, length 32 03:35:01.549158 IP 192.168.1.170.35684 > 192.168.1.1.53: 43557+ A? connectivitycheck.android.com. (47) 03:35:01.549334 IP 192.168.1.170.43378 > 192.168.1.1.53: 12979+ A? connectivitycheck.android.com. (47) 03:35:01.549422 IP6 fe80::XXXX:XXXX:XXXX:XXXX > fe80::XXXX:XXXX:XXXX:XXXX: ICMP6, neighbor advertisement, tgt is fe80::XXXX:XXXX:XXXX:XXXX, length 32 03:35:01.558617 IP 192.168.1.1.53 > 192.168.1.170.43378: 12979 1/0/0 A 216.58.221.174 (63) 03:35:01.559263 IP 192.168.1.1.53 > 192.168.1.170.35684: 43557 1/0/0 A 216.58.221.206 (63) 03:35:01.575683 IP 192.168.1.170.51055 > 192.168.1.1.53: 36811+ AAAA? ipv4only.arpa. (31) 03:35:01.575771 IP 192.168.1.1.53 > 192.168.1.170.51055: 36811 0/0/0 (31) 03:35:01.577961 IP 192.168.1.170.40382 > 192.168.1.1.53: 53548+ A? ipv4only.arpa. (31) 03:35:01.578023 IP 192.168.1.1.53 > 192.168.1.170.40382: 53548 2/0/0 A 192.0.0.171, A 192.0.0.170 (63) 03:35:01.700229 IP 192.168.1.170.41658 > 192.168.1.1.53: 56266+ AAAA? north-america.pool.ntp.org. (44) 03:35:01.722678 IP 192.168.1.1.53 > 192.168.1.170.41658: 56266 0/1/0 (99) 03:35:01.727875 IP 192.168.1.170.55498 > 192.168.1.1.53: 51322+ A? north-america.pool.ntp.org. (44) 03:35:01.749989 IP 192.168.1.1.53 > 192.168.1.170.55498: 51322 4/0/0 A 38.229.71.1, A 206.108.0.132, A 104.156.99.226, A 69.167.160.102 (108) 03:35:01.751144 IP 192.168.1.170.33118 > 216.58.221.206.80: Flags [S], seq 2110605975, win 65535, options [mss 1460,sackOK,TS val 4294940628 ecr 0,nop,wscale 7], length 0 03:35:01.755148 IP 192.168.1.170.33459 > 38.229.71.1.123: NTPv3, Client, length 48 03:35:01.764984 IP 216.58.221.206.80 > 192.168.1.170.33118: Flags [S.], seq 2111217721, ack 2110605976, win 42540, options [mss 1414,sackOK,TS val 1370227089 ecr 4294940628,nop,wscale 7], length 0 03:35:01.767118 IP 192.168.1.170.33118 > 216.58.221.206.80: Flags [.], ack 1, win 685, options [nop,nop,TS val 4294940630 ecr 1370227089], length 0 03:35:01.770321 IP 192.168.1.170.33118 > 216.58.221.206.80: Flags [P.], seq 1:430, ack 1, win 685, options [nop,nop,TS val 4294940630 ecr 1370227089], length 429 03:35:01.783798 IP 216.58.221.206.80 > 192.168.1.170.33118: Flags [.], ack 430, win 341, options [nop,nop,TS val 1370227108 ecr 4294940630], length 0 03:35:01.783914 IP 216.58.221.206.80 > 192.168.1.170.33118: Flags [P.], seq 1:103, ack 430, win 341, options [nop,nop,TS val 1370227108 ecr 4294940630], length 102 03:35:01.784154 IP 216.58.221.206.80 > 192.168.1.170.33118: Flags [F.], seq 103, ack 430, win 341, options [nop,nop,TS val 1370227108 ecr 4294940630], length 0 03:35:01.786455 IP 192.168.1.170.33118 > 216.58.221.206.80: Flags [.], ack 103, win 685, options [nop,nop,TS val 4294940632 ecr 1370227108], length 0 03:35:01.786945 IP 192.168.1.170.33118 > 216.58.221.206.80: Flags [F.], seq 430, ack 104, win 685, options [nop,nop,TS val 4294940632 ecr 1370227108], length 0 03:35:01.800821 IP 216.58.221.206.80 > 192.168.1.170.33118: Flags [.], ack 431, win 341, options [nop,nop,TS val 1370227125 ecr 4294940632], length 0 (snip) 03:35:31.574015 IP 192.168.1.170.64782 > 192.168.1.1.53: 53427+ AAAA? inaz2.hatenablog.com. (38) 03:35:31.583433 IP 192.168.1.1.53 > 192.168.1.170.64782: 53427 0/1/0 (122) (snip) 03:35:31.610380 IP 192.168.1.170.42707 > 192.168.1.1.53: 43177+ A? inaz2.hatenablog.com. (38) (snip) 03:35:31.684565 IP 192.168.1.1.53 > 192.168.1.170.42707: 43177 1/0/0 A 52.197.171.58 (54) (snip)
上の結果から、接続したAndroid端末の通信をキャプチャできていることが確認できる。
注意事項
作成したアクセスポイントは、適切なパスフレーズを設定し、自身の利用においてのみ使用すること。 無断で第三者の通信を取得した場合、不正アクセス禁止法等に抵触するおそれがある。
関連リンク
整流回路とオペアンプ増幅回路でWi-Fi電波を可視化してみる
次のページを参考に簡易電界強度計を作り、Wi-Fi 2.4GHzの電波強度をLEDで可視化してみる。
部品調達
- ブレッドボード(参考)
- ジャンパワイヤセット(参考)
- ショットキーバリアダイオード1N60×2(参考)
- 汎用オペアンプLM358AN×1(参考)
- LM358N(参考)は不可
- 1/4Wカーボン抵抗1kΩ×2、1MΩ×1(参考)
- 積層セラミックコンデンサ0.01μF×2(参考)
- 5mm高輝度LED×1(参考)
- 006P型9V電池および電池ケース(参考)
- アンテナ用すずメッキ線(針金、ジャンパワイヤでも可)
回路図
上のページで利用しているショットキーバリアダイオード1SS108は生産終了品になっているので、代わりに1N60を用い、次のような回路を作る。
上の回路は、アンテナに生じる交流電圧を倍電圧整流回路(左半分、動作イメージ)で直流にし、オペアンプによる非反転増幅回路(右半分、動作イメージ)で電圧を増幅する。
ここで、非反転増幅回路における増幅率は 1 + 1MΩ/1kΩ = 1001倍
である。
また、二つの回路の間にある抵抗は、オペアンプのプラス側とマイナス側に流れる電流の差(バイアス電流)を打ち消すためのものであり、その抵抗値は1kΩと1MΩの並列抵抗の値(約1kΩ)となる。
アンテナには、2.4GHz(波長12.49cm)で共振する、次のような半波長ダイポールアンテナを用いる。 ここでは、すずメッキ線を切って作ったが、針金やジャンパワイヤで作ってもよい。
また、LM358ANには二つのオペアンプが入っており、ピン配置は次のようになっている(データシートより引用)。
実際にブレッドボード上に作った回路の写真を次に示す。
Wi-Fi電波を可視化してみる
2.4GHz通信を有効にした無線ブロードバンドルータに近づけてみると、次の動画のようになる。
同じく2.4GHz帯の電波を利用する電子レンジに近づけてみると、次の動画のように、より強くLEDが光ることがわかる。