<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title>Posts on omoikane.dev</title>
		<link>https://www.omoikane.dev/posts/</link>
		<description>Recent content in Posts on omoikane.dev</description>
		<generator>Hugo -- gohugo.io</generator>
		<language>en-us</language>
		<copyright>This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.</copyright>
		<lastBuildDate>Sun, 16 Aug 2020 03:50:29 +0900</lastBuildDate>
		<atom:link href="https://www.omoikane.dev/posts/index.xml" rel="self" type="application/rss+xml" />
		
		<item>
			<title>GNURadio QuadratureDemodブロックのアルゴリズム</title>
			<link>https://www.omoikane.dev/posts/algorithm-of-quadraturedemod/</link>
			<pubDate>Sun, 16 Aug 2020 03:50:29 +0900</pubDate>
			
			<guid>https://www.omoikane.dev/posts/algorithm-of-quadraturedemod/</guid>
			<description>TL;DR FSKをGNURadioで復調する時に使う、QuadratureDemodブロックは、$n$番目のサンプリングで得られたI/Q値を \[ \begin{aligned} x_n &amp;amp;=</description>
			<content type="html"><![CDATA[<h2 id="tldr">TL;DR</h2>
<p>FSKをGNURadioで復調する時に使う、<code>QuadratureDemod</code>ブロックは、$n$番目のサンプリングで得られたI/Q値を
\[
\begin{aligned} x_n &amp;= A\mathrm{e}^{j\omega t + \phi}\\ &amp;= \mathrm{exp}(2 \pi j\frac{F_n}{F_s}n + \phi) \end{aligned}
\]
としたとき、</p>
<p>\[
\mathrm{arg}(x_n \times x_{n-1}^*)
\]
を計算している。これはI/Q信号を極座標表示した時の偏角の時間微分であり、まさに周波数である。
ただし、$F_s$はサンプリング周波数、$F_n$は信号波の周波数とする。</p>
<hr>
<p>GNURadioのWikiにある、<a href="https://wiki.gnuradio.org/index.php/Quadrature_Demod">Quadrature Demod</a>を見ていたら、以下の記述があった。</p>
<blockquote>
<p>Mathematically, this block calculates the product of the one-sample delayed input and the conjugate undelayed signal, and then calculates the argument of the resulting complex number&hellip;
(数学的に、このブロックは、1サンプル遅れた入力と、遅れていない信号の複素共役の積を求め、出てきた複素数の偏角を計算する)</p>
</blockquote>
<p>とある。この文章の後、数式がかかれているようだが、なぜか数式がレンダリングされない。というか、$\TeX$の構文が画像になっている。せっかくなので、ちょっと式をフォローしてみよう。</p>
<h2 id="任意のサンプリングにおける周波数の算出">任意のサンプリングにおける周波数の算出</h2>
<p>SDRで受信して出てきたI/Q信号は、複素数で書ける。任意の時刻$t$における信号$x$は、</p>
<p>\[
x = A\mathrm{e}^{j\omega t}
\]
と書ける。ここで、$\omega = 2 \pi f$は角振動数であり、$A$は振幅である。</p>
<p>SDRでは、サンプリング周波数$F_s$の周期$T_s = \frac{1}{F_s}$毎に取得されたI/Q信号が得られる。よって、$n$番目のサンプリングを得た時刻$t$は、$t = T_s n$であるから、
$n$番目のサンプリングで得たI/Q信号は</p>
<p>\[
x_n = A\mathrm{exp} [j\omega_n T_s n + \phi]
\]
となる。ここで、$\omega_n$はn番目のサンプリングで得られたI/Q信号の角周波数、また$\mathrm{exp}(a) = \mathrm{e}^a$である。</p>
<p>求める値は、</p>
<blockquote>
<p>1サンプル遅れた入力と、遅れていない信号の複素共役の積を求め、出てきた複素数の偏角</p>
</blockquote>
<p>であるから、以下の式になる。</p>
<p>\[
Y_n = \mathrm{arg} [x_{n-1} \times x_n^* ]
\]</p>
<p>まず、右辺括弧内を計算しよう。計算は簡単。手の運動。</p>
<p>\[
\begin{aligned} y_n &amp;= x_{n-1} \times x_n^* \\ &amp;= A\mathrm{exp} [j\omega_{n-1} T_s (n-1) + \phi] \times A\mathrm{exp} [-(j\omega_{n} T_s n + \phi)] \\ &amp;= A^2\mathrm{exp} [j\omega_{n-1} T_s (n-1) + \phi -(j\omega_{n} T_s n + \phi)] \\ &amp;= A^2\mathrm{exp} [jT_s \{  n(\omega_{n-1} - \omega_n) - \omega_{n-1} \}] \\  &amp;= A^2\mathrm{exp} [jTs \{ \frac{\omega_{n-1} - \omega_n}{\omega_n}n - \omega_{n-1} \}] \end{aligned}
\]</p>
<p>ここで、FSKの周波数偏移を$\delta f$とすると、 $|\omega_{n-1} - \omega_n| \le 2\delta\omega$である。FSKの場合、キャリア周波数に比べて周波数偏差は充分小さい。たとえば、920MHz帯で50kbpsであれば、周波数偏移25kHzである。よって、</p>
<p>\[
|\omega_{n-1} - \omega_n| \le 2\delta\omega \ll \omega_n
\]</p>
<p>となり、
\[
\frac{\omega_{n-1} - \omega_n}{\omega_n} \approx 0
\]
と近似することができる。
前述の例に適用して確認してみると、</p>
<p>\[
\frac{2\times 50 \times 10^3}{920 \times 10^6} \approx \times 10^{-4}
\]
となる。あまり良い近似ではないが、実用上問題ないだろう。</p>
<p>以上のことから、
\[
\begin{aligned} y_n &amp;\approx A^2\mathrm{exp}(-jT_s \omega_{n-1}) \\ Y_n &amp;\approx \mathrm{arg}(y_n) \\ &amp;= -T_s \omega_{n-1} = -2\pi \frac{F_{n-1}}{F_s} \end{aligned}
\]
となる。</p>
<h2 id="結果の評価">結果の評価</h2>
<p>げげげっ。$F_{n-1}$も$F_s$も周波数なので0より大きいから、$Y_n$が負の値になってしまう。
物理的に考えると、$Y_n$は、複素数の偏角の時間微分、すなわち周波数を計算しているのであるから$Y_n$は正の実数でなければならない。</p>
<p>考えてみると、$Y_n$は、$n-1$番目の偏角から$n$番目の偏角を引いている。これは引き算の順序が逆である。そういえば、件の文章の後の数式もちゃんと$\TeX$を読んでみると、</p>
<p>\[
y[n] = &hellip;. = \mathrm{arg} (A\mathrm{e}^{j 2\pi \frac{f}{f_s}n + \phi_0} \mathrm{e}^{-j 2\pi \frac{f}{f_s} (n-1)})
\]</p>
<p>みたいなことが書いてある。これって、$n$番目から$n-1$番目の偏角を引いている&hellip;
だまされた。</p>
<p>ということで、GNURadioのQuadrature DemodのWikiおよびドキュメントは間違っていて、
たとえば、</p>
<blockquote>
<p>Mathematically, this block calculates the product of the undelayed input and the complex conjugate of the one-sample delayed signal, and then calculates the argument of the resulting complex number</p>
</blockquote>
<p>と修正すべきである。</p>
<p>一応、ソースを見て私が間違ってないか確認しなきゃ。</p>
]]></content>
		</item>
		
		<item>
			<title>数式のテスト</title>
			<link>https://www.omoikane.dev/posts/mathtest/</link>
			<pubDate>Sat, 15 Aug 2020 17:23:47 +0900</pubDate>
			
			<guid>https://www.omoikane.dev/posts/mathtest/</guid>
			<description>HugoのThemeをアップデートして、$\KaTeX$ を使った数式をレンダリングできるようにしたのでテスト。 \[ e^{i\pi} + 1 = 0 \] ふむ。 \[ \begin{aligned}\nabla \cdot \mathbf{B} &amp;amp;=</description>
			<content type="html"><![CDATA[<p>HugoのThemeをアップデートして、$\KaTeX$ を使った数式をレンダリングできるようにしたのでテスト。</p>
<p>\[
e^{i\pi} + 1 = 0
\]</p>
<p>ふむ。</p>
<p>\[
\begin{aligned}\nabla \cdot \mathbf{B} &amp;= 0\\  \nabla \times \mathbf{E} &amp;= -\frac{\partial\mathbf{E}}{\partial t}\\ \nabla \cdot \mathbf{D} &amp;= \rho\\ \nabla \times \mathbf{H}  &amp;= \mathbf{j} + \frac{\partial \mathbf{D}}{\partial t}
\end{aligned}
\]</p>
<p>式の整列もできてる。フォントもきれい。</p>
]]></content>
		</item>
		
		<item>
			<title>AWS KMSでの手動キーローテーション</title>
			<link>https://www.omoikane.dev/posts/kmskeyrotation/</link>
			<pubDate>Fri, 07 Aug 2020 16:50:59 +0900</pubDate>
			
			<guid>https://www.omoikane.dev/posts/kmskeyrotation/</guid>
			<description>TL;DR あるAWS Security関連の教科書に、KMSの手動ローテーションは、鍵を新規作成して 古い鍵を削除する旨の記述があり、「古い鍵を削除した</description>
			<content type="html"><![CDATA[<h2 id="tldr">TL;DR</h2>
<p>あるAWS Security関連の教科書に、KMSの手動ローテーションは、鍵を新規作成して
古い鍵を削除する旨の記述があり、「古い鍵を削除したら復号できなくなるじゃないのか？」
と思ったので検証してみた。</p>
<p>KMSのAPIに、ReEncryptというキーローテーションのためのAPIが用意されており、これを使うと、新しい鍵でData Keyを再暗号化できる。
よって管理しているData Keyをすべて再暗号化すれば、ローテーションされた古い鍵を削除することができる。</p>
<p>また手動キーローテーションは、以下の手順がよさそうだ。</p>
<ol>
<li>新しい鍵を生成 (CreateKey)</li>
<li>ローテートする鍵のエイリアスを新しい鍵に継承 (UpdateAlias)</li>
<li>古い鍵で暗号化したData Keyを新しい鍵で再暗号化 (ReEncrypt)</li>
<li>古い鍵の削除予約 (ScheduleKeyDeletion)</li>
</ol>
<hr>
<h2 id="introduction">Introduction</h2>
<p>AWS KMS 開発者ガイドの<a href="https://docs.aws.amazon.com/ja_jp/kms/latest/developerguide/rotate-keys.html">手動でのキーローテーション</a>には、以下の注釈がある。</p>
<blockquote>
<p>新しい CMK の使用を開始するときに、元の CMK を有効なままにすれば、AWS KMS は元の CMK により暗号化されたデータを復号できます。データを復号するとき、KMS はデータの暗号化に使用された CMK を識別し、同じ CMK を使用して復号します。元の CMK と新しいものの両方が有効である限り、AWS KMS はどちらの CMK によって暗号化されたデータでも復号できます。</p>
</blockquote>
<p>鍵が有効、すなわち削除または無効化しなければ復号できるとある。まぁそれはそうだろう。
しかしこれは、教科書とは異なっているため、検証してみた。</p>
<h2 id="鍵の削除保留期間中に復号可能かどうか確認">鍵の削除保留期間中に復号可能かどうか確認</h2>
<p>まず、前回作成した鍵を削除予約し、削除保留状態にする。</p>
<pre><code>$ aws kms schedule-key-deletion --key-id a99dd0c2-494f-4650-99ba-811078e86390
{
    &quot;KeyId&quot;: &quot;arn:aws:kms:ap-northeast-1:xxxxxxxxxxxxx:key/a99dd0c2-494f-4650-99ba-811078e86390&quot;,
    &quot;DeletionDate&quot;: 1599436800.0
}
</code></pre><p>鍵の状態を確認すると、<code>PendingDeletion</code>になっており、削除保留状態であることがわかる。</p>
<pre><code>$ aws kms describe-key --key-id a99dd0c2-494f-4650-99ba-811078e86390 \
 	--output text  --query KeyMetadata.KeyState
PendingDeletion
</code></pre><p>では、この鍵を使って復号するとどうなるか。</p>
<pre><code>$ aws kms decrypt --ciphertext-blob  fileb://encrypted_datakey.bin \
	--key-id a99dd0c2-494f-4650-99ba-811078e86390

An error occurred (KMSInvalidStateException) when calling the Decrypt operation: arn:aws:kms:ap-northeast-1:xxxxxxxxxxxxx:key/a99dd0c2-494f-4650-99ba-811078e86390 is pending deletion.
</code></pre><p>ですよねー</p>
<p>ちなみに無効のときも、ちゃんとエラーが返る。</p>
<pre><code>$ aws kms decrypt --ciphertext-blob  fileb://encrypted_datakey.bin \
	--key-id a99dd0c2-494f-4650-99ba-811078e86390

An error occurred (DisabledException) when calling the Decrypt operation: arn:aws:kms:ap-northeast-1:xxxxxxxxxxxxx:key/a99dd0c2-494f-4650-99ba-811078e86390 is disabled.
</code></pre><h2 id="data-key-reencryption">Data Key ReEncryption</h2>
<p>なーんだ、教科書まちがってんじゃん。まぁよくあるよねーで済まそうと思っていたのだが、
AWSのAPIドキュメントに、ReEncryptというActionがあるのに気がついた。
<a href="https://docs.aws.amazon.com/ja_jp/kms/latest/APIReference/API_ReEncrypt.html">KMS APIドキュメントのReEncrypt</a>の冒頭に以下の記述がある。</p>
<blockquote>
<p>Decrypts ciphertext and then reencrypts it entirely within AWS KMS. You can use this operation to change the customer master key (CMK) under which data is encrypted, such as when you manually rotate a CMK or change the CMK that protects a ciphertext.<br>
（AWS KMSの内部で暗号化されたデータを復号したあと、再暗号化する。
この操作は、手動ローテートまたはデータを保護しているCMKの変更といった、
暗号化されたデータのCMKの変更に使用することができる。）</p>
</blockquote>
<p>あーCMKのmanually rotateに使うって書いてあるよ。
ということで、Data Keyを新しい鍵で再暗号化することで、古い鍵を削除することができるようだ。</p>
<p>せっかくなので、検証。</p>
<pre><code>$ aws kms re-encrypt --ciphertext-blob fileb://encrypted_datakey.bin \
    --source-key-id a99dd0c2-494f-4650-99ba-811078e86390 \
    --destination-key-id 0676925f-cf0f-4dd3-b44e-28019abc4b4f
{
    &quot;CiphertextBlob&quot;: &quot;AQICAHiU/sFZekLEdu8fd/KEweZKipeRYu7IFuTQhYEqP/GM5wEBgW7RhOZ5GNPgKKOIcPrTAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMMLNzPFHv5pC5TMKeAgEQgDvrQ+/LP8dwZy/joqeZIa8bnbfzKEfTHEXxsrWtRZyhOCcJhMTqhBPf7KhruU2kMqDIeA7ZhyRs8I93fQ==&quot;,
    &quot;SourceKeyId&quot;: &quot;arn:aws:kms:ap-northeast-1:xxxxxxxxxxxxx:key/a99dd0c2-494f-4650-99ba-811078e86390&quot;,
    &quot;KeyId&quot;: &quot;arn:aws:kms:ap-northeast-1:xxxxxxxxxxxxx:key/0676925f-cf0f-4dd3-b44e-28019abc4b4f&quot;,
    &quot;SourceEncryptionAlgorithm&quot;: &quot;SYMMETRIC_DEFAULT&quot;,
    &quot;DestinationEncryptionAlgorithm&quot;: &quot;SYMMETRIC_DEFAULT&quot;
}
</code></pre><p>おーできたー</p>
<p>CybertextBlobのBase64エンコードを解いてre-encrypted_datakey.binに格納したあと、再暗号化に使用した鍵で復号する。</p>
<pre><code>$ aws kms decrypt --key-id 0676925f-cf0f-4dd3-b44e-28019abc4b4f --ciphertext-blob fileb://re-encrypted_datakey.bin --output text --query Plaintext|base64 -d &gt;decrypted_datakey.bin
</code></pre><p>で、オリジナルのハッシュと比較する。</p>
<pre><code>$ sha256sum datakey.bin decrypted_datakey.bin 
0ce2033e1f0aff4508ebf82612e59c449d11bf0e5e50a6ac7fc95337989f9b84  datakey.bin
0ce2033e1f0aff4508ebf82612e59c449d11bf0e5e50a6ac7fc95337989f9b84  decrypted_datakey.bin
</code></pre><p>一致した。ということで、Data Keyの再暗号化に成功したことがわかる。</p>
<h2 id="key-aliasの継承">Key aliasの継承</h2>
<p>鍵のローテーションにより、Key aliasを新しい鍵に継承する必要がある。
そこで、UpdateAliasオペレーションをつかう。</p>
<pre><code>$ aws kms update-alias --alias-name alias/aestest --target-key-id 0676925f-cf0f-4dd3-b44e-28019abc4b4f
</code></pre><p>このオペレーションには、KeyPolicyのaliasを、<code>kms:UpdateAlias</code> できるIAMロールが必要なので注意。</p>
<p>継承が終わったあと、古い鍵はまだ有効であるが、Aliasは削除されている。
よって、手動の鍵のローテーションは以下の手順が良さそうだ。</p>
<ol>
<li>新しい鍵を生成 (CreateKey)</li>
<li>ローテートする鍵のエイリアスを新しい鍵に継承 (UpdateAlias)</li>
<li>古い鍵で暗号化したData Keyを新しい鍵で再暗号化 (ReEncrypt)</li>
<li>古い鍵の削除予約 (ScheduleKeyDeletion)</li>
</ol>
<h2 id="まとめ">まとめ</h2>
<p>KMSの手動によるキーローテーションでは、ReEncryptオペレーションを使うとData KeyのCMKを変更することができる。古い鍵を有効にしておくこともできるが、鍵一つにつき1USD/monthのキーストレージの使用料金がかかってしまう。また、ローテーションするときには、新しい鍵を生成後、Aliasを新しい鍵に継承したあと、Data Keyの再暗号化処理を行うと良い。</p>
]]></content>
		</item>
		
		<item>
			<title>AWS KMSによる、データの暗号化と復号 - 対称鍵編</title>
			<link>https://www.omoikane.dev/posts/kmsdemo2/</link>
			<pubDate>Fri, 07 Aug 2020 16:48:41 +0900</pubDate>
			
			<guid>https://www.omoikane.dev/posts/kmsdemo2/</guid>
			<description>対称鍵はかんたん。 鍵の作成 Management ConsoleでもCLIでもお好みで。 以下のパラメータでCMK (Customer Management Key)を作成する。 キーのタイプ: 対称 キーマテ</description>
			<content type="html"><![CDATA[<p>対称鍵はかんたん。</p>
<h2 id="鍵の作成">鍵の作成</h2>
<p>Management ConsoleでもCLIでもお好みで。
以下のパラメータでCMK (Customer Management Key)を作成する。</p>
<ul>
<li>キーのタイプ: <code>対称</code></li>
<li>キーマテリアルオリジン: <code>KMS</code></li>
</ul>
<h2 id="鍵情報の取得">鍵情報の取得</h2>
<p>CLIで、describe-keyを使って鍵の情報を得る。</p>
<pre><code>$ aws kms describe-key --key-id alias/aestest
{
    &quot;KeyMetadata&quot;: {
        &quot;AWSAccountId&quot;: &quot;xxxxxxxxxxxxx&quot;,
        &quot;KeyId&quot;: &quot;a99dd0c2-494f-4650-99ba-811078e86390&quot;,
        &quot;Arn&quot;: &quot;arn:aws:kms:ap-northeast-1:xxxxxxxxxxxxx:key/a99dd0c2-494f-4650-99ba-811078e86390&quot;,
        &quot;CreationDate&quot;: 1596705473.686,
        &quot;Enabled&quot;: true,
        &quot;Description&quot;: &quot;&quot;,
        &quot;KeyUsage&quot;: &quot;ENCRYPT_DECRYPT&quot;,
        &quot;KeyState&quot;: &quot;Enabled&quot;,
        &quot;Origin&quot;: &quot;AWS_KMS&quot;,
        &quot;KeyManager&quot;: &quot;CUSTOMER&quot;,
        &quot;CustomerMasterKeySpec&quot;: &quot;SYMMETRIC_DEFAULT&quot;,
        &quot;EncryptionAlgorithms&quot;: [
            &quot;SYMMETRIC_DEFAULT&quot;
        ]
    }
}
</code></pre><h2 id="data-keyの取得">Data Keyの取得</h2>
<p>generate-data-keyで、平文のData Keyと暗号化されたData Keyが落ちてくる。</p>
<pre><code>$ aws kms generate-data-key --key-id alias/aestest --key-spec AES_256
{
    &quot;CiphertextBlob&quot;: &quot;AQIDAHizJ7k8Iy6GrPV/ExEn64vrdh6dhDbGez4hVZW2oP6C1gFj7ZyUbuDUX6..&quot;,
    &quot;KeyId&quot;: &quot;arn:aws:kms:ap-northeast-1:xxxxxxxxxxxxx:key/a99dd0c2-494f-4650-99ba-811078e86390&quot;
}
</code></pre><p>CiphertextBlobは復号時に必要になるので、DynamoDB等で別途管理する。
平文のData Key(Plaintext)をdatakeyに格納し、この鍵を使って、データを暗号化する。</p>
<h2 id="データの暗号化">データの暗号化</h2>
<p>平文のData Keyを使って普通に暗号化する。</p>
<pre><code>openssl aes-256-cbc -e -\
    in plain_data \
    -pass file:plain_datakey \
    -out encrypted_data \
    -pbkdf2
</code></pre><p>暗号化が終わったら、平文のData Keyは<strong>必ず</strong>削除すること。
これを怠るとKMSを使う意味がない。</p>
<h2 id="データの復号">データの復号</h2>
<p>別途管理していた、暗号化されたData Keyをkmsで復号して、Data Keyを取得する。
暗号化されたData Keyが、Base64エンコードされてencrypted_datakey.txtに格納されていた場合、
base64デコード後、kmsを使ってData Keyを復号する。</p>
<pre><code>$ base64 -d encrypted_datakey.txt &gt;encrypted_datakey
$  aws kms decrypt --key-id alias/aestest \
    --ciphertext-blob fileb://encrypted_datakey \
    --output text --query Plaintext | base64 -d &gt;decrypted_datakey
</code></pre><p>Data Keyが、decrypted_datakeyに格納されたので、データが復号できる。</p>
<pre><code>$ openssl aes-256-cbc -d \
    -in encrypted_data \
    -out decrypted_data \
    --pass file:decrypted_datakey \
    -pbkdf2
</code></pre><pre><code>$ sha256sum plain_data.bin decrypted_data.bin 
5678c5a7a63f910c6eb172ebb3736b73099b8d62172c6b42034d87b7bf30b107  plain_data
5678c5a7a63f910c6eb172ebb3736b73099b8d62172c6b42034d87b7bf30b107  decrypted_data
</code></pre><p>一致した。復号が成功したことがわかる。</p>
<p>Have Fun!</p>
]]></content>
		</item>
		
		<item>
			<title>AWS KMSによる、データの暗号化と復号 - 非対称鍵（RSA_4096）編</title>
			<link>https://www.omoikane.dev/posts/kmsdemo1/</link>
			<pubDate>Fri, 07 Aug 2020 16:41:49 +0900</pubDate>
			
			<guid>https://www.omoikane.dev/posts/kmsdemo1/</guid>
			<description>AWS KMSでを使ったデータの暗号化、復号の検証も行った。 対称鍵の検証は、別記事にした。 鍵の作成 Management ConsoleでもCLIでもお好みで。 以下のパ</description>
			<content type="html"><![CDATA[<p>AWS KMSでを使ったデータの暗号化、復号の検証も行った。
対称鍵の検証は、<a href="../kmsdemo2">別記事</a>にした。</p>
<h2 id="鍵の作成">鍵の作成</h2>
<p>Management ConsoleでもCLIでもお好みで。
以下のパラメータでCMK (Customer Management Key)を作成する。</p>
<ul>
<li>キーのタイプ: <code>非対称</code></li>
<li>キーの使用: <code>暗号化および復号化</code></li>
<li>キーの仕様: <code>RSA_4098</code></li>
<li>Alias: <code>rsatest</code></li>
</ul>
<h2 id="鍵情報の取得">鍵情報の取得</h2>
<p>CLIで、describe-keyを使って鍵の情報を得る。</p>
<pre><code> aws kms describe-key --key-id alias/rsatest
{
    &quot;KeyMetadata&quot;: {
        &quot;AWSAccountId&quot;: &quot;xxxxxxxxxxxxx&quot;,
        &quot;KeyId&quot;: &quot;0192e16e-01ed-4d84-84a5-5144259766f2&quot;,
        &quot;Arn&quot;: &quot;arn:aws:kms:ap-northeast-1:xxxxxxxxxxxxx:key/0192e16e-01ed-4d84-84a5-5144259766f2&quot;,
        &quot;CreationDate&quot;: 1596690475.888,
        &quot;Enabled&quot;: true,
        &quot;Description&quot;: &quot;&quot;,
        &quot;KeyUsage&quot;: &quot;ENCRYPT_DECRYPT&quot;,
        &quot;KeyState&quot;: &quot;Enabled&quot;,
        &quot;Origin&quot;: &quot;AWS_KMS&quot;,
        &quot;KeyManager&quot;: &quot;CUSTOMER&quot;,
        &quot;CustomerMasterKeySpec&quot;: &quot;RSA_4096&quot;,
        &quot;EncryptionAlgorithms&quot;: [
            &quot;RSAES_OAEP_SHA_1&quot;,
            &quot;RSAES_OAEP_SHA_256&quot;
        ]
    }
}
</code></pre><h2 id="公開鍵の取得">公開鍵の取得</h2>
<p>4096bitの鍵長をもつRSA鍵ペアができている。
秘密鍵を取り出すことはできないが、公開鍵は取り出せる。</p>
<pre><code> aws kms get-public-key --key-id alias/rsatest
{
    &quot;KeyId&quot;: &quot;arn:aws:kms:ap-northeast-1:xxxxxxxxxxxxx:key/0192e16e-01ed-4d84-84a5-5144259766f2&quot;,
    &quot;PublicKey&quot;: &quot;MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA6u875H89mRNP7PLH6+QGEhPUIga6jrssgmLnC/98KGXfZx/jHYPH2oJw0uedA0uuu3wUbubduy8rYd+5LfQUiLoK+2cjOHp/u2xbKruDmZtVM68YNWBnYwp8bZ9y7c2VWblBgu0WPWa1NFGMi2reXcqDHppvzy15lv5kYYrfKKjabbluPOSDYYp4Hsw8Dmd/6tvc7zw1L+Qa4uyK/ojp05WPSVmlaUMuKopzr3ngD/sEKwQ1BmA0dWGzTUZTtOAQusSlLN7tCoLNLWKS1ZDfZJKbiVBLbErGiyLRhGt7MaXgB95O+Xh9wgdiCHFZ/S2ji68VCXEfrTomcy63kdctM7EmNWhgnBHGBgxelQSG9gwqCBciKBkVuCP594N3xVjN2T1DgbsMaznfN8+P03gfvOqwtD8LVXS87JuVAJb3iBm5hfH5m+/NL8vSZ9itamPPDVNG8hBnl2ZUCK2wZBMzw2djRIyUAe+9N1NwzoYTSNlsWC5KJTH5yIat99v3IRAhHMugwfaaKmpUauLdPxQf2vI4wLE/ZNGYR4f9IhPgs1VEpxVGYge198YPbeDzEdbTUIGMDR7kCTSXrt5JZRW/40RX/Rh6qq12Jo55TC6PVaGtMcLjz7LYiMdgeBZq4/TV6EbovuEo/x5MNyVMpWjR4o45LqQuw8983c++55zFju0CAwEAAQ==&quot;,
    &quot;CustomerMasterKeySpec&quot;: &quot;RSA_4096&quot;,
    &quot;KeyUsage&quot;: &quot;ENCRYPT_DECRYPT&quot;,
    &quot;EncryptionAlgorithms&quot;: [
        &quot;RSAES_OAEP_SHA_1&quot;,
        &quot;RSAES_OAEP_SHA_256&quot;
    ]
}
</code></pre><p>JSON形式では使いにくいので、Base64エンコードを解いてDERに変換する。</p>
<pre><code>$ aws kms get-public-key \
	--key-id alias/rsatest \
	--output text --query PublicKey|base64 -d &gt;pubkey.der
</code></pre><p>pubkey.derが生成される。</p>
<h2 id="データの暗号化">データの暗号化</h2>
<p>kmsでは、4kByteまでしかデータを暗号化および復号ができない。そのため暗号化および復号に使用する鍵を独自に生成する。
この鍵をData Keyと呼ぶ。このData KeyをKMSで作成した鍵で暗号化し、別途DynamoDBなどで管理する。
これによりkmsでData Keyを復号する権限のないユーザにデータの復号はできなくなる。
鍵の管理については本稿では触れない。</p>
<h3 id="data-keyの生成">Data Keyの生成</h3>
<p>データの暗号化アルゴリズムはお好みで。今回はAES256-CBCにしよう。まずは、opensslで鍵を生成する。</p>
<pre><code>$ openssl rand -out datakey 32
</code></pre><h3 id="data-keyの暗号化">Data Keyの暗号化</h3>
<h4 id="opensslを使用する場合">OpenSSLを使用する場合</h4>
<p>Data Keyをkmsで生成したCMKで暗号化する。さきほど取得した公開鍵で暗号化する。
kmsで復号できるアルゴリズムは限られているので注意が必要である。
データを復号するときには、kmsに暗号化したData Keyを復号してもらわなければならない。
そのため、kmsが復号できるアルゴリズムを使用する必要がある。</p>
<p>サポートしているアルゴリズムは、described-keyで取得できる。
今回の場合は、<code>RSAES_OAEP_SHA_1</code>と<code>RSAES_OAEP_SHA_256</code>の二種類である。</p>
<p>ということで、今回は、<code>RSAES_OAEP_SHA_256</code>でData Keyを暗号化する。</p>
<pre><code>$ openssl pkeyutl -encrypt \
    -pubin -inkey pubkey.der -keyform DER \
    -in datakey \
    -out encrypted_datakey \
    -pkeyopt rsa_padding_mode:oaep \
    -pkeyopt rsa_oaep_md:sha256
</code></pre><p>一応、ちゃんとkmsで復号できるか確認しておこう。</p>
<pre><code>$ aws kms decrypt \
    --ciphertext-blob fileb://encrypted_datakey \
    --key-id alias/rsatest \
    --encryption-algorithm RSAES_OAEP_SHA_256 \
    --output text --query Plaintext | base64 -d &gt;decrypted_datakey
</code></pre><p>kmsで復号されたData keyは、decrypted_datakeyに格納された。
暗号化前のData keyと復号されたData keyのHashを比較する。</p>
<pre><code>$  sha256sum datakey decrypted_datakey 
0b9d181063f1e4ace5ac59e1253186406b27fb1ffd0c22bb1a62ffa2515f6803  datakey
0b9d181063f1e4ace5ac59e1253186406b27fb1ffd0c22bb1a62ffa2515f6803  decrypted_datakey
</code></pre><p>一致した。復号に成功していることが確認できた。</p>
<h4 id="kmsにおまかせする場合">kmsにおまかせする場合</h4>
<p>上記の例では、opensslコマンドを使ったが、もちろんkmsに任せることもできる。
こっちのほうが簡単か。ただAPI利用料がかかる。</p>
<pre><code> $ aws kms encrypt --key-id alias/rsatest \
    --plaintext fileb://datakey \
    --encryption-algorithm RSAES_OAEP_SHA_256
{
    &quot;CiphertextBlob&quot;: &quot;ZAo40r0pQ3COzELKzM8mJMFNbHno4jUiyzeuZ6rQVUH0ZLsIJbdESnhl....&quot;,
    &quot;KeyId&quot;: &quot;arn:aws:kms:ap-northeast-1:xxxxxxxxxxxxx:key/0192e16e-01ed-4d84-84a5-5144259766f2&quot;,
    &quot;EncryptionAlgorithm&quot;: &quot;RSAES_OAEP_SHA_256&quot;
}
</code></pre><h2 id="データの暗号化-1">データの暗号化</h2>
<p>データを暗号化する。これは普通にopensslで</p>
<pre><code>$ openssl aes-256-cbc -e \
    -in plain_data.bin \
    -out encrypted_data.bin
    -pass file:datakey \
    -pbkdf2
</code></pre><p>暗号化したら、暗号化に使用したData Keyを削除する。
これを忘れるとkmsを使う意味がまったくなくなってしまう。</p>
<pre><code>$ rm datakey
</code></pre><h2 id="データの復号">データの復号</h2>
<p>データを復号するには、まず暗号化されたData Keyを復号する。</p>
<pre><code>$ aws kms decrypt \
    --ciphertext-blob fileb://encrypted_datakey \
    --key-id alias/rsatest \
    --encryption-algorithm RSAES_OAEP_SHA_256 \
    --output text --query Plaintext | base64 -d &gt;decrypted_datakey
</code></pre><p>そして、データを復号する。</p>
<pre><code>$ openssl aes-256-cbc -d \
    -in encrypted_data.bin \
    -out decrypted_data \
    -pass file:./decrypted_datakey \
    -pbkdf2
</code></pre><p>復号できたデータは、decrypted_dataに格納されている。
確認のため、平文のデータのHashと比較する。</p>
<pre><code>$ sha256sum plain_data.bin decrypted_data.bin 
5678c5a7a63f910c6eb172ebb3736b73099b8d62172c6b42034d87b7bf30b107  plain_data.bin
5678c5a7a63f910c6eb172ebb3736b73099b8d62172c6b42034d87b7bf30b107  decrypted_data.bin
</code></pre><p>一致した。復号が成功したことがわかる。</p>
<p>Have Fun!</p>
]]></content>
		</item>
		
		<item>
			<title>中国製の顕微鏡画像をLinux PCに取り込む方法</title>
			<link>https://www.omoikane.dev/posts/capturing-microscope/</link>
			<pubDate>Sat, 30 May 2020 00:00:00 +0900</pubDate>
			
			<guid>https://www.omoikane.dev/posts/capturing-microscope/</guid>
			<description>ずいぶん前にaliexpressで購入したLCD顕微鏡画像をLinux PCで取りむことができた。 何をいまさら感が漂っているだろうが、自分用に</description>
			<content type="html"><![CDATA[<p>ずいぶん前にaliexpressで購入したLCD顕微鏡画像をLinux PCで取りむことができた。
何をいまさら感が漂っているだろうが、自分用にメモしておく。</p>
<p>現在、使用している顕微鏡はこれ。型番は不明。同僚にaliexpressから買ってもらったもの。</p>
<p><img src="./microscope.png" alt="aliexpressで買った型番不明のLCD顕微鏡"></p>
<p>これを、PCのUSBポートに接続して、lsusbコマンドを叩くと、謎のデバイスが見えた。</p>
<pre><code>Bus 001 Device 012: ID 1908:3256 GEMBIRD 
</code></pre><p>カメラが見えているか確認。v4l2-ctlコマンドは、v4l-utilsパッケージに入っている。</p>
<pre><code>$ v4l2-ctl --list-devices
TIGA   Device: TIGA   Device (usb-0000:00:14.0-2.3):
        /dev/video0
        /dev/video1
        /dev/media0
</code></pre><p>おぉ。見えている。サポートしているフォーマットを確認する。</p>
<pre><code>$ v4l2-ctl --list-formats-ext
ioctl: VIDIOC_ENUM_FMT
        Type: Video Capture

        [0]: 'YUYV' (YUYV 4:2:2)
                Size: Discrete 640x480
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 320x240
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 160x120
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 1280x720
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 176x144
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
</code></pre><p>640x480 30fpsをサポートしているようだ。</p>
<p>vlcを起動して、[メディア]→[キャプチャーデバイスを開く]→[詳細設定オプション]
をクリックする。幅と高さに640、480を、フレームレートに30を入力する。
他はデフォルトのままでOK。</p>
<p><img src="./dialog.png" alt="詳細設定オプションダイアログ"></p>
<p>入力したらOKボタンでダイアログを閉じ、再生ボタン押下で取り込みが始まる。</p>
<p><img src="./captured.png" alt="取り込まれた顕微鏡画像"></p>
<p>もちろんvlcでスナップショットも取れる。これまでLDCをデジカメで撮ってたけど
これでいろいろはかどる。</p>
]]></content>
		</item>
		
		<item>
			<title>GDALでGCOM-Cの可視領域のデータからTrue Colorイメージを再構成してみた</title>
			<link>https://www.omoikane.dev/posts/gcomc-gdal/</link>
			<pubDate>Sat, 07 Dec 2019 00:00:00 +0900</pubDate>
			
			<guid>https://www.omoikane.dev/posts/gcomc-gdal/</guid>
			<description>この記事は、FOSS4G Advent Calendar 2019 の12月7日の記事です。 昨日の記事は、 northprintさんの「mapboxのMaps SDK for Androidでお</description>
			<content type="html"><![CDATA[<p>この記事は、<a href="https://qiita.com/advent-calendar/2019/foss4g">FOSS4G Advent Calendar 2019</a> の12月7日の記事です。
昨日の記事は、 northprintさんの「<a href="https://northprint.net/?p=255">mapboxのMaps SDK for Androidでお好みのラスタータイルを表示する</a>」
でした。</p>
<h2 id="tldr">TL;DR</h2>
<p>今回は2017年の12月に打ち上げられた、気候変動観測衛星「しきさい」(GCOM-C)の可視領域の数値データを、
GDAL2.4で再構成することで、True Color Imageに再構成してみました。</p>
<p>結果は、こんな感じになりました。欠損値は透明にしてあります。</p>
<p><img src="./GC1SG1_20191101D01M.png" alt="">
(Original data provided by JAXA)</p>
<p>あと再構成プログラムをC++で書きましたが、Pythonのほうがよかったかも&hellip;</p>
<h2 id="しきさいの概要">「しきさい」の概要</h2>
<p>気候変動観測衛星「しきさい」は、地球環境変動観測ミッション(GCOM)の陸域版の衛星です。
GCOMは地球から放射される様々な光を長期間観測することで、地球の気候変動の監視と
メカニズムの解明を目的としたプロジェクトです。水循環を観測するGCOM-Wと、気候変動を観測する
GCOM-Cという二つの衛星で観測を行っています。
GCOM-Cに搭載されている、SGLIという多波長光学放射計は、可視、近赤外、近紫外領域の
19の観測波長帯を持っています。</p>
<p>今回は可視領域の観測データを使って目視に近い画像である、True Colorイメージを作成してみます。</p>
<h2 id="データの入手方法">データの入手方法</h2>
<p>まずは、GCOM-Cの観測データを入手しましょう。
JaxaのG-Portal(<a href="https://gportal.jaxa.jp/gpr/">https://gportal.jaxa.jp/gpr/</a>) というページでユーザー登録をすると、FTPで
データをダウンロードすることができます。また、G-PortalのWebサイトにログインすると
データの検索やダウンロード、フォーマット変換ができるようです。
私はデータ変換を自動化する必要がある別の目的があるので、あえて自分でやることにします。
詳しくは
「<a href="https://gportal.jaxa.jp/gpr/assets/mng_upload/COMMON/upload/GPortalUserManual_ja.pdf">G-Portal 地球観測衛星データ提供システムユーザ向け取扱説明書</a>」と
「<a href="https://gportal.jaxa.jp/gpr/assets/mng_upload/GCOM-C/GCOM-C_SHIKISAI_Data_Users_Handbook_jp.pdf">気候変動観測衛星「しきさい」(GCOM-C) データ利用ハンドブック</a>」を参照してください。</p>
<p>それでは、FTPサーバにログインして、/standard/GCOM-C/GCOM-C.SGLI 以下にある、L3.LAND.RV03、L3.LAND.RV05、L3.LAND.RV07 から同じ日付のデータを
ダウンロードします。</p>
<p>今回は2019年11月の1ヶ月間に観測された平均値を使用しました。ダウンロードしたファイルは以下のとおりです。</p>
<ul>
<li>GC1SG1_20191101D01M_D0000_3MSG_RV03F_1001.h5</li>
<li>GC1SG1_20191101D01M_D0000_3MSG_RV05F_1001.h5</li>
<li>GC1SG1_20191101D01M_D0000_3MSG_RV07F_1001.h5</li>
</ul>
<p>ファイル名の後ろのほうにある、RV03、RV05、RV07はプロダクトIDとよばれる観測から得られた物理量の種類を
示すIDです。RVxxのIDを持つプロダクトは陸域の大気補正済みの反射率で、RV03が青、RV06が緑、RV07が赤の光に
相当します。</p>
<p>各データに関しては
「<a href="https://gportal.jaxa.jp/gpr/assets/mng_upload/GCOM-C/SGLI_Higher_Level_Product_Format_Description_jp.pdf">SGLI高次プロダクト フォーマット説明書</a>」
を参照してください。</p>
<h2 id="データの再構成">データの再構成</h2>
<p>では、ダウンロードしたデータを再構成していきます。ダウンロードしたファイルはHDF5という形式で保存されています。
HDF5はデータやパラメータを階層的に保存できる形式で、観測値だけでなく観測した時間や、処理したアルゴリズム、パラメータ等も
いっしょに一つのファイルに格納できるすぐれものです。このHDF5形式のファイルからデータを取り出して、GDALを使って
GTiff形式に変換します。</p>
<p>可視画像は、R、G、Bの3つピクセルから構成されています。GTiffでは、それぞれ別のバンドに格納すれば良いので、
取り出したデータを各バンドにコピーするだけでOKです。簡単ですね。</p>
<p>以下のプログラムは、HDF5とGDALのライブラリを使用しています。DebianやUbuntuを使用している方は、</p>
<div class="highlight"><pre class="chroma"><code class="language-sh" data-lang="sh">$ sudo apt install libgdal-dev libhdf5-dev
</code></pre></div><p>で必要なライブラリをインストールすることができます。</p>
<p>C++なので、あまりちょっととっつきにくいかもしれませんが、流れはコメントに書いたとおりです。
同じ流れでPythonで書くことができるはずです。</p>
<div class="highlight"><pre class="chroma"><code class="language-C++" data-lang="C++"><span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
	<span class="c1">// GDALの初期化
</span><span class="c1"></span>	<span class="n">GDALAllRegister</span><span class="p">();</span>
	
	<span class="c1">// Dataを格納する配列
</span><span class="c1"></span>	<span class="kt">uint16_t</span> <span class="n">data</span><span class="p">[</span><span class="n">WIDTH</span><span class="p">][</span><span class="n">HEIGHT</span><span class="p">];</span>

	<span class="c1">// File名が長いので、定数化
</span><span class="c1"></span>	<span class="k">static</span> <span class="k">const</span> <span class="n">string</span> <span class="n">RED</span>   <span class="o">=</span> <span class="s">&#34;GC1SG1_20191101D01M_D0000_3MSG_RV03F_1001.h5&#34;</span><span class="p">;</span>
	<span class="k">static</span> <span class="k">const</span> <span class="n">string</span> <span class="n">GREEN</span> <span class="o">=</span> <span class="s">&#34;GC1SG1_20191101D01M_D0000_3MSG_RV05F_1001.h5&#34;</span><span class="p">;</span>
	<span class="k">static</span> <span class="k">const</span> <span class="n">string</span> <span class="n">BLUE</span>  <span class="o">=</span> <span class="s">&#34;GC1SG1_20191101D01M_D0000_3MSG_RV07F_1001.h5&#34;</span><span class="p">;</span>


	<span class="c1">// GDALのGTiffドライバを呼び出す
</span><span class="c1"></span>	<span class="n">GDALDriver</span> <span class="o">*</span><span class="n">poDriver</span> <span class="o">=</span> <span class="n">GetGDALDriverManager</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">GetDriverByName</span><span class="p">(</span><span class="s">&#34;GTiff&#34;</span><span class="p">);</span>
	<span class="c1">// 呼び出したドライバで、BANDを4つもったデータセットを作成
</span><span class="c1"></span>	<span class="n">GDALDataset</span> <span class="o">*</span><span class="n">poDstDS</span> <span class="o">=</span> <span class="n">poDriver</span><span class="o">-&gt;</span><span class="n">Create</span><span class="p">(</span> <span class="s">&#34;out.tiff&#34;</span><span class="p">,</span> <span class="n">WIDTH</span><span class="p">,</span> <span class="n">HEIGHT</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="n">GDT_Byte</span><span class="p">,</span> <span class="k">nullptr</span><span class="p">);</span>

	<span class="c1">// 1番目のバンドを取り出して
</span><span class="c1"></span>	<span class="n">band</span> <span class="o">=</span> <span class="n">poDstDS</span><span class="o">-&gt;</span><span class="n">GetRasterBand</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
	<span class="c1">// このバンドを赤に指定する
</span><span class="c1"></span>	<span class="n">band</span><span class="o">-&gt;</span><span class="n">SetColorInterpretation</span><span class="p">(</span><span class="n">GCI_RedBand</span><span class="p">);</span>
	<span class="c1">// HDF5からデータを読んでから
</span><span class="c1"></span>	<span class="n">readData</span><span class="p">(</span><span class="n">RED</span><span class="p">,</span> <span class="n">data</span><span class="p">,</span> <span class="s">&#34;/Image_data/Rs_VN07_AVE&#34;</span><span class="p">);</span>
	<span class="c1">// 取り出したバンドにコピーする。
</span><span class="c1"></span>	<span class="n">copy2band</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">band</span><span class="p">);</span>

	<span class="c1">// 2番目は緑。赤と同様
</span><span class="c1"></span>	<span class="n">GDALRasterBand</span> <span class="o">*</span><span class="n">band</span> <span class="o">=</span> <span class="n">poDstDS</span><span class="o">-&gt;</span><span class="n">GetRasterBand</span><span class="p">(</span><span class="mi">2</span><span class="p">);</span>
	<span class="n">band</span><span class="o">-&gt;</span><span class="n">SetColorInterpretation</span><span class="p">(</span><span class="n">GCI_GreenBand</span><span class="p">);</span>
	<span class="n">readData</span><span class="p">(</span><span class="n">GREEN</span><span class="p">,</span> <span class="n">data</span><span class="p">,</span> <span class="s">&#34;/Image_data/Rs_VN05_AVE&#34;</span><span class="p">);</span>
	<span class="n">copy2band</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">band</span><span class="p">);</span>

	<span class="c1">// 3番目は青。赤と同様
</span><span class="c1"></span>	<span class="n">band</span> <span class="o">=</span> <span class="n">poDstDS</span><span class="o">-&gt;</span><span class="n">GetRasterBand</span><span class="p">(</span><span class="mi">3</span><span class="p">);</span>
	<span class="n">band</span><span class="o">-&gt;</span><span class="n">SetColorInterpretation</span><span class="p">(</span><span class="n">GCI_BlueBand</span><span class="p">);</span>
	<span class="n">readData</span><span class="p">(</span><span class="n">BLUE</span><span class="p">,</span> <span class="n">data</span><span class="p">,</span> <span class="s">&#34;/Image_data/Rs_VN03_AVE&#34;</span><span class="p">);</span>
	<span class="n">copy2band</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">band</span><span class="p">);</span>

	<span class="c1">// 4番目はアルファチャンネル。欠損値を透明にする
</span><span class="c1"></span>	<span class="n">band</span> <span class="o">=</span> <span class="n">poDstDS</span><span class="o">-&gt;</span><span class="n">GetRasterBand</span><span class="p">(</span><span class="mi">4</span><span class="p">);</span>
	<span class="n">band</span><span class="o">-&gt;</span><span class="n">SetColorInterpretation</span><span class="p">(</span><span class="n">GCI_AlphaBand</span><span class="p">);</span>
	<span class="n">genAlphaBand</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">band</span><span class="p">,</span> <span class="n">WIDTH</span><span class="p">,</span> <span class="n">HEIGHT</span><span class="p">);</span>

	<span class="c1">// 最後にデータセットをクローズしてできあがり
</span><span class="c1"></span>	<span class="n">GDALClose</span><span class="p">(</span><span class="n">poDstDS</span><span class="p">);</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</code></pre></div><p>HDFからデータを取り出すreadDataは、
ただデータを取り出して、引数に指定されたアドレスにコピーしているだけです。が、
使用しているHDFライブラリでは、DataSpaceにデータを格納するのがお作法のようです。
コピーするためには、コピー元とコピー先の範囲を指定必要があります。
変数spとmemspaceのselectAll関数を呼ぶことで、DataSpace全体を指定しています。</p>
<div class="highlight"><pre class="chroma"><code class="language-C++" data-lang="C++"><span class="kt">void</span> <span class="nf">readData</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">filename</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">data</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">dataset</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">H5File</span> <span class="n">file</span><span class="p">(</span><span class="n">filename</span><span class="p">.</span><span class="n">c_str</span><span class="p">(),</span> <span class="n">H5F_ACC_RDONLY</span><span class="p">);</span>
    <span class="n">DataSet</span> <span class="n">ds</span> <span class="o">=</span> <span class="n">grp</span><span class="p">.</span><span class="n">openDataSet</span><span class="p">(</span><span class="n">dataset</span><span class="p">.</span><span class="n">c_str</span><span class="p">());</span>

    <span class="n">DataSpace</span> <span class="n">sp</span> <span class="o">=</span> <span class="n">ds</span><span class="p">.</span><span class="n">getSpace</span><span class="p">();</span>
    <span class="k">const</span> <span class="kt">int</span> <span class="n">rank</span> <span class="o">=</span> <span class="n">sp</span><span class="p">.</span><span class="n">getSimpleExtentNdims</span><span class="p">();</span>
    <span class="n">hsize_t</span> <span class="n">count</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="n">WIDTH</span><span class="p">,</span> <span class="n">HEIGHT</span><span class="p">,</span> <span class="mi">1</span><span class="p">};</span>
    <span class="n">hsize_t</span> <span class="n">offset</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">};</span>
    <span class="n">sp</span><span class="p">.</span><span class="n">selectAll</span><span class="p">();</span>

    <span class="n">DataSpace</span> <span class="n">memspace</span><span class="p">(</span><span class="n">rank</span><span class="p">,</span> <span class="n">count</span><span class="p">);</span>
    <span class="n">memspace</span><span class="p">.</span><span class="n">selectAll</span><span class="p">();</span>
    <span class="n">ds</span><span class="p">.</span><span class="n">read</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">PredType</span><span class="o">::</span><span class="n">NATIVE_UINT16</span><span class="p">,</span> <span class="n">memspace</span><span class="p">,</span> <span class="n">sp</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div><p>取り出したデータをbandにコピーするcopy2bandは、以下のとおりです。
データをスキャンして、欠損値を意味する65535を0にして、
14ビットのデータを6bit右シフトして8bitに丸めてたあと、bandにコピーしています。</p>
<div class="highlight"><pre class="chroma"><code class="language-C++" data-lang="C++"><span class="kt">void</span> <span class="nf">copy2band</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">data</span><span class="p">,</span> <span class="n">GDALRasterBand</span> <span class="o">*</span><span class="n">band</span><span class="p">)</span>
<span class="p">{</span>
	<span class="c1">// dataを2次元配列としてアクセスしたいので、memcpyで配列にコピー
</span><span class="c1"></span>	<span class="kt">uint16_t</span> <span class="n">val</span><span class="p">[</span><span class="n">WIDTH</span><span class="p">][</span><span class="n">HEIGHT</span><span class="p">];</span>
	<span class="n">memcpy</span><span class="p">(</span><span class="n">val</span><span class="p">,</span> <span class="n">data</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="kt">uint16_t</span><span class="p">)</span> <span class="o">*</span> <span class="n">width</span> <span class="o">*</span> <span class="n">height</span><span class="p">);</span>
    
	<span class="kt">uint8_t</span> <span class="n">pixel</span><span class="p">[</span><span class="n">WIDTH</span><span class="p">][</span><span class="n">HEIGHT</span><span class="p">];</span>

	<span class="c1">// すべてのデータをスキャンしてデータサイズを8ビットに変換
</span><span class="c1"></span>	<span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">y</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">y</span> <span class="o">&lt;</span> <span class="n">HEIGHT</span><span class="p">;</span> <span class="n">y</span><span class="o">++</span><span class="p">)</span>
		<span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">x</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">x</span> <span class="o">&lt;</span> <span class="n">width</span><span class="p">;</span> <span class="n">x</span><span class="o">++</span><span class="p">)</span>
			<span class="n">pixel</span><span class="p">[</span><span class="n">x</span><span class="p">][</span><span class="n">y</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">val</span><span class="p">[</span><span class="n">x</span><span class="p">][</span><span class="n">y</span><span class="p">]</span> <span class="o">==</span> <span class="mi">65535</span><span class="p">)</span> <span class="o">?</span> <span class="mi">0</span> <span class="o">:</span> <span class="p">(</span><span class="n">val</span><span class="p">[</span><span class="n">x</span><span class="p">][</span><span class="n">y</span><span class="p">]</span> <span class="o">&gt;&gt;</span> <span class="mi">6</span><span class="p">);</span>
	<span class="c1">// バンドにコピー
</span><span class="c1"></span>	<span class="n">band</span><span class="o">-&gt;</span><span class="n">RasterIO</span><span class="p">(</span><span class="n">GF_Write</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">WIDTH</span><span class="p">,</span> <span class="n">HEIGHT</span><span class="p">,</span> <span class="n">pixel</span><span class="p">,</span> <span class="n">WIDTH</span><span class="p">,</span> <span class="n">HEIGHT</span><span class="p">,</span> <span class="n">GDT_Byte</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div><p>最後にアルファチャンネルを生成しているgenAlphaBand関数はこんな感じにしました。</p>
<div class="highlight"><pre class="chroma"><code class="language-C++" data-lang="C++"><span class="kt">void</span> <span class="nf">genAlphaBand</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">data</span><span class="p">,</span> <span class="n">GDALRasterBand</span> <span class="o">*</span><span class="n">band</span><span class="p">)</span>
<span class="p">{</span>
        <span class="kt">uint16_t</span> <span class="n">val</span><span class="p">[</span><span class="n">WIDTH</span><span class="p">][</span><span class="n">HEIGHT</span><span class="p">];</span>
        <span class="n">memcpy</span><span class="p">(</span><span class="n">val</span><span class="p">,</span> <span class="n">data</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="kt">uint16_t</span><span class="p">)</span> <span class="o">*</span> <span class="n">WIDTH</span> <span class="o">*</span> <span class="n">HEIGHT</span><span class="p">);</span>
        <span class="kt">uint8_t</span> <span class="n">tmp</span><span class="p">[</span><span class="n">WIDTH</span><span class="p">][</span><span class="n">HEIGHT</span><span class="p">];</span>
        <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">y</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">y</span> <span class="o">&lt;</span> <span class="n">HEIGHT</span><span class="p">;</span> <span class="n">y</span><span class="o">++</span><span class="p">)</span>
                <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">x</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">x</span> <span class="o">&lt;</span> <span class="n">WIDTH</span><span class="p">;</span> <span class="n">x</span><span class="o">++</span><span class="p">){</span>
                        <span class="n">tmp</span><span class="p">[</span><span class="n">x</span><span class="p">][</span><span class="n">y</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">val</span><span class="p">[</span><span class="n">x</span><span class="p">][</span><span class="n">y</span><span class="p">]</span> <span class="o">==</span> <span class="mi">65535</span><span class="p">)</span> <span class="o">?</span> <span class="mi">0</span> <span class="o">:</span> <span class="mi">255</span><span class="p">;</span>
                <span class="p">}</span>
        <span class="n">band</span><span class="o">-&gt;</span><span class="n">RasterIO</span><span class="p">(</span><span class="n">GF_Write</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">WIDTH</span><span class="p">,</span> <span class="n">HEIGHT</span><span class="p">,</span> <span class="n">tmp</span><span class="p">,</span> <span class="n">WIDTH</span><span class="p">,</span> <span class="n">HEIGHT</span><span class="p">,</span> <span class="n">GDT_Byte</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div><p>ほぼcopy2bandと同じです。違うのは欠損値だった場合は値を0、そうでないときは255を使用しているだけです。
ここもそうですが、全体的にリファクタリングの余地がありますね。</p>
<p>結果はTL;DRのところに載せたとおりです。
実行する時は、確実にスタック領域が不足するので、ulimitコマンドでスタック領域を無制限にすることを忘れずに。
さもないとSegmentation Faultで落ちます。</p>
<div class="highlight"><pre class="chroma"><code class="language-sh" data-lang="sh">$ <span class="nb">ulimit</span> -s unlimited
</code></pre></div><p>今回は、GCOM-Cの可視光のデータを使ってTrue Color Imageを再構成してみました。
GCOM-Cは可視光以外にも、海水面温度や地表面温度、海の色、エアロゾル、雲頂高度といった興味深い値を観測し、
その数値データを数日遅れで入手することができます。</p>
<p>興味がある方は、ぜひ他のデータも可視化してみてください。</p>
<p>明日は、Kanahiroさんです。</p>
]]></content>
		</item>
		
		<item>
			<title>OpenBSD6.5をuEFI対応PCにインストールする方法</title>
			<link>https://www.omoikane.dev/posts/install-openbsd65/</link>
			<pubDate>Sat, 08 Jun 2019 21:24:29 +0900</pubDate>
			
			<guid>https://www.omoikane.dev/posts/install-openbsd65/</guid>
			<description>TL;DR OpenBSDのインストール記事が少ないということで、ちょうど6.5がリリースされたのでインストール記事を書いておく。 と思ったら、「Ope</description>
			<content type="html"><![CDATA[<h2 id="tldr">TL;DR</h2>
<ol>
<li>
<p>OpenBSDのインストール記事が少ないということで、ちょうど6.5がリリースされたのでインストール記事を書いておく。
と思ったら、「<a href="https://qiita.com/ki3nichiro/items/a2ed08d14d2d46e28fca">OpenBSD 6.5 のインストール</a>」という良記事があった。以下の3点以外同じなので、そちらを参照のこと。</p>
</li>
<li>
<p>OpenBSDはuEFIからのブートをサポートしている。パーティションの作成時に、</p>
<pre><code>Use (W)hole disk MBR, whole disk (G)PT, or (E)dit? [W]
</code></pre><p>``</p>
</li>
</ol>
<p>と聞かれたら、<code>G</code>を選べばよい。</p>
<ol>
<li>
<p>ネットワークインターフェースのファームウェアがインストーラーに含まれていない場合でも、インストールが可能である。
インストール完了後に、別途ダウンロードしてファームウェアをUSBメモリ等で転送し、<code>fw_update</code>コマンドでインストールすれば良い。</p>
</li>
<li>
<p>今となっては、信じられないくらいチョー不親切に見えるCUIベースのインストーラーなので、VierualBox等の仮想マシンにインストールしてみると、練習ができて安心。</p>
</li>
</ol>
<hr>
<h2 id="0-インストールメディアの作成">0. インストールメディアの作成</h2>
<p>まずはインストールに必要なメディアを作成する。
イメージは、https://www.openbsd.org/faq/faq4.html#Download にリンクがある。
installXX.fsのamd64のリンクをクリックすればダウンロード可能である。
また、SHA256ファイルもダウンロードしておく。</p>
<div class="highlight"><pre class="chroma"><code class="language-sh" data-lang="sh">wget https://cdn.openbsd.org/pub/OpenBSD/6.5/amd64/install65.fs
wget https://cdn.openbsd.org/pub/OpenBSD/6.5/amd64/SHA256
</code></pre></div><p>ダウンロードしたイメージがダウンロードに成功しているか確認する。</p>
<div class="highlight"><pre class="chroma"><code class="language-sh" data-lang="sh">ha256sum -c SHA256 --ignore-missing 
install65.fs: 完了
</code></pre></div><p>成功！</p>
<p>あとは、USBメモリにダウンロードしたイメージを書き込む。</p>
<pre><code>dd if=install65.fs of=/dev/sdb
</code></pre><h2 id="1-インストーラーの実行">1. インストーラーの実行</h2>
<p>作成したUSBメモリをPCに差し、USBメモリから起動するとインストーラーが起動する。
OpenBSDのインストーラーはテキストベースで、GUIのインストーラーなど存在しないので注意。</p>
<p>まず最初に、</p>
<pre><code>Welcome to the OpenBSD/amd64 installation program.
(I)nstall, (U)pgrade, (A)utoinstall or (S)hell
</code></pre><p>と聞かれるので、<code>I</code>を押してインストールを選択する。</p>
<h3 id="11-キーボード選択">1.1 キーボード選択</h3>
<pre><code>Choose your keyboard layout (? or 'L' for list) [default]
</code></pre><p>キーボードレイアウトを選択する。英語キーボードを使っている人はdefaultで良ので、Enterキーを押下する。
日本語キーボードの人は、<code>jp</code>と入力する。</p>
<h3 id="12-ホストネーム設定">1.2 ホストネーム設定</h3>
<pre><code>System hostname? (short form, e.g. 'foo')
</code></pre><p>ホスト名を入力する。個人で使用する場合は、適当なPC名を入力する。
会社など、誰かが管理しているネットワークで使用する場合は、ネットワーク管理者の指示を仰ぐ。</p>
<h3 id="13-ネットワークの設定">1.3 ネットワークの設定</h3>
<h4 id="131-設定するインターフェースの選択">1.3.1 設定するインターフェースの選択</h4>
<pre><code>Available network interfaces are: iwm0 vlan0.
Which network interface do you wish to configure? (or 'done')[iwm0]
</code></pre><p>インストーラーが自動検出したネットワークインターフェースを列挙して、
どのインターフェースを設定するか聞いてくる。</p>
<p>iwm0とvlan0が検出できたようだ。ここはインストールするPCで異なるだろう。
私がインストールしているPCのネットワークインターフェースは、有線LANがなくWiFiだけしか持っていない。
iwm0がWiFiのインターフェースだろう。ということで、iwm0を選択する。</p>
<p>有線LANがある人は、有線LANで設定した方が楽だろう。</p>
<h4 id="132-wifiの設定">1.3.2 WiFiの設定</h4>
<pre><code>Access point? (ESSID, 'any' list# or '?')[any]
</code></pre><p>WiFiのESSIDを入力する。</p>
<pre><code>Security protocol? (O)pen, (W)ep, WPA-(P)SK [O]
</code></pre><p>WPA-PSKであれば、<code>P</code>を、WEPであれば、<code>W</code>を選択する。</p>
<pre><code>WPA passphrase? (will echo)
</code></pre><p>WPA-PSKを選択すれば、WPAパスフレーズを、WEPを選択するとWEPキーを聞かれるので、入力する。</p>
<h4 id="133-ipアドレスの設定">1.3.3 IPアドレスの設定</h4>
<pre><code>IPv4 address for iwm0? (or 'dhcp' or 'none')[dhcp]
</code></pre><p>選択したネットワークインターフェースのIPアドレスを設定する。
固定IPを設定するのであれば、<code>192.0.2.123</code>のように入力する。DHCPで自動設定す場合は、<code>dhcp</code>、
アドレスを付けない場合は、<code>none</code>を入力する。</p>
<pre><code>iwm0: could not read firmware iwm-8265-22 (error 2)
iwm0: fail to load init firmware
iwm0: aquiring device failed
iwm0: aquiring device failed
iwm0: aquiring device failed
iwm0: SIOCSIFFLAGS: No such file or directory
iwm0: no link ........ sleeping
</code></pre><p>げげげっ ファームウェアがないのでネットワークに接続できないと言われてしまった&hellip;orz</p>
<p>しょうがないので、インストールさ行を続けて、インストール後にファームウェアを入れることにしよう。
追加のファームウェアが必要ない場合は、普通にアドレスが設定されます。</p>
<pre><code>IPv6 address for iwm0? (or 'autoconf' or 'none')[none]
</code></pre><p>IPv6のアドレスを指定する。IPv6を使わないのであれば、<code>none</code>を、自動設定を行うなら<code>autoconf</code>を選択する。
固定のIPv6アドレスを使う場合は、<code>2001:db8::1</code>のように指定する。</p>
<pre><code>Available network interfaces are: iwm0 vlan0.
Whitch network interface do you wish to configure? (or 'done')[iwm0]
</code></pre><p>とまた聞かれるので、必要なら他のインターフェースを選択して、ネットワーク設定を繰り返す。
ネットワーク設定が終わったら、<code>done</code>を入力し、ドメイン名の設定に進む。</p>
<h4 id="134-ドメイン名の設定">1.3.4 ドメイン名の設定</h4>
<pre><code>DNS domain name? (e.g. `example.com`)[my.domain]
</code></pre><p>PCのドメイン名を入力する。
ホスト名同様、会社など、誰かが管理しているネットワークで使用する場合は、ネットワーク管理者の指示を仰ぐ。
個人で自分のドメインを持っていない人は、デフォルトの<code>my.domain</code>でよいでしょう。</p>
<h4 id="135-dnsサーバの設定">1.3.5 DNSサーバの設定</h4>
<pre><code>DNS servers? (IP address list or 'none')[none]
</code></pre><p>DHCPでIPv4アドレスの設定に成功していれば、取得したアドレスがデフォルト値に設定されているはず。
なので、Enterキーを押下するだけで良いと思う。
私は失敗したので、<code>8.8.8.8</code>を入力した。</p>
<h3 id="14-rootパスワードの設定">1.4 rootパスワードの設定</h3>
<pre><code>Password for root account? (will not echo)
</code></pre><p>管理者アカウントのログインパスワードを設定する。入力した文字は表示されないので注意。</p>
<h3 id="15-sshサーバ自動起動の設定">1.5 sshサーバ自動起動の設定</h3>
<pre><code>Start sshd(8) by default? [yes]
</code></pre><p>sshサーバを自動起動するか聞かれる。サーバ用途の場合は起動しても良いだろう。
デスクトップといった、リモートログインが必要ない用途であれば起動する必要はない。</p>
<h3 id="16-デスクトップマネージャー自動起動の設定">1.6 デスクトップマネージャー自動起動の設定</h3>
<pre><code>Do you want the X Window System to be started by xenodm(1)? [no]
</code></pre><p>xenodmというデスクトップマネージャーを使ってX Wondow Systemを自動起動するかと聞かれる。
<code>yes</code>にすると、起動時にGUIのログイン画面が表示される。サーバ用途では<code>no</code>にする。</p>
<h3 id="17-一般ユーザの作成">1.7 一般ユーザの作成</h3>
<pre><code>Setup a user? (enter a lower-case login name or `no`)
</code></pre><p>ここで一般ユーザーを作成する場合は、小文字でログイン名を、必要なければ<code>no</code>を入力する。</p>
<h3 id="18-sshでのrootログインの可否の設定">1.8 sshでのrootログインの可否の設定</h3>
<pre><code>WARNING: root is targeted by password guessing attacks, pubkeys are safer.
Allow root ssh login? (yes, no, prohibit-password) [no]
</code></pre><p>sshでrootログインを許すかどうか設定する。
許可する場合は&rsquo;yes&rsquo;、禁止する場合は&rsquo;no&rsquo;、パスワード認証を禁止し、公開鍵認証であれば許可する場合は、<code>prohibit-password</code>
を入力する。一般にrootでリモートログインする理由はないので、<code>no</code>で良いだろう。
なんらかの理由でrootによるリモートログインが必要なら、<code>prohibit-password</code>を設定して、公開鍵認証を使用すべきである。</p>
<h3 id="19-パーティションの設定">1.9 パーティションの設定</h3>
<pre><code>Available disks are: sd0 sd1
Which disk is the root disk? ('?' for details)[sd0]
</code></pre><p>OpenBSDをインストールするディスクを指定する。&rsquo;?&lsquo;を入力するとsd0,sd1が何を指しているかが表示される。
私のPCの場合、sd0がハードディスクで、sd1がUSBメモリだった。</p>
<p>インストールするディスクを指定すると、指定したディスクのパーティションテーブルが表示され、その後に</p>
<pre><code>Use (W)hole disk MBR, whole disk (G)PT, or (E)dit? [W]
</code></pre><p>と聞かれる。ディスク全体を使う場合は<code>G</code>を指定する。ここで<code>G</code>を指定しないとuEFIでは起動できない。</p>
<p><code>G</code>を選択すると、パーティションを自動設定した場合のレイアウトが表示されたあと、
自動設定を採用するか、変更するか聞かれる。</p>
<pre><code>#                size           offset  fstype [fsize bsize   cpg]
  a:          2097152             1024  4.2BSD   2048 16384 12958 # /
  b:         33598688          2098176    swap                    # none
  c:       1953525168                0  unused                    
  d:          8388608         35696864  4.2BSD   2048 16384 12958 # /tmp
  e:         74537408         44085472  4.2BSD   2048 16384 12958 # /var
  f:          4194304        118622880  4.2BSD   2048 16384 12958 # /usr
  g:          2097152        122817184  4.2BSD   2048 16384 12958 # /usr/X11R6
  h:         41943040        124914336  4.2BSD   2048 16384 12958 # /usr/local
  i:              960               64   MSDOS                    
  j:          4194304        166857376  4.2BSD   2048 16384 12958 # /usr/src
  k:         12582912        171051680  4.2BSD   2048 16384 12958 # /usr/obj
  l:        629145536        183634624  4.2BSD   4096 32768 26062 # /home
Use (A)uto layout, (E)dit auto layout, or create (C)ustom layout?[a]
</code></pre><p>自動で良ければ<code>a</code>を、自動設定をベースに変更するなら<code>E</code>を、カスタムなレイアウトにする場合は<code>C</code>を入力する。
パーティションの設定が終わると、パーティションを作成してフォーマットを始める。
特に確認はないので、マルチブートをするときなど、既存のシステムを消さないように注意する。</p>
<p>ファイルシステムの作成が終わったら、</p>
<pre><code>Available disks are: sd1
Which disk do you wish to initialize? (or 'done')[done]
</code></pre><p>と聞かれる。これ以上初期化するディスクが無ければ<code>done</code>を入力する。</p>
<h3 id="110-インストールセットの指定">1.10 インストールセットの指定</h3>
<pre><code>Let's install the sets!
Location of sets? (disk http or done)[http]
</code></pre><p>ネットワーク設定に成功した人は、httpを指定する。今回、私はファームウェアが足りずネットワーク設定に失敗したため<code>disk</code>を
選択することにする。</p>
<pre><code>Is the disk partition already mounted? [yes]
</code></pre><p>ディスクパーティションが既にマウントされているかだと？ディスクパーティションとは何を指すのかな。よくわからんので、デフォルトの<code>yes</code>で。</p>
<pre><code>Pathname to the sets? (or 'done')[6.5/amd64]
</code></pre><p>しらんがな。ひとまずデフォルトで。</p>
<pre><code>The directory '6.5/amd64' dose not exist.
</code></pre><p>デスヨネー</p>
<pre><code>Pathname to the sets? (or 'done')[6.5/amd64]
</code></pre><p>では、<code>done</code>で逃げる。</p>
<pre><code>Location of sets? (disk http or done)[disk]
</code></pre><p>もどった。<code>disk</code>を選択。</p>
<pre><code>Is the disk partition already mounted? [yes]
</code></pre><p>さっきはyesでダメだったので、<code>no</code>にする。</p>
<pre><code>Available disks are: sd0 sd1
Which is disj contains the install media? (or 'done') [sd1] 
</code></pre><p><code>sd1</code>がUSBメモリだったので、<code>sd1</code>を指定。</p>
<pre><code>a:     920512    1024  4.2BSD    2048  16384  16142
i:        960      64   MSDOS
Available sd1 partitions are: a i
Which sd1 partition has the install sets? (or 'done')[a]
</code></pre><p>インストールメディアのUSBメモリは2つのパーティションに分かれているのか。
まぁインストールセットが入っているのは、きっと<code>a</code>でしょう。
パーティションタイプが4.2BSDだし、なによりもサイズがでかい。</p>
<pre><code>Pathname to the sets? (or 'done')[6.5/amd64]
</code></pre><p>これはデフォルトの<code>6.5/amd64</code>で。</p>
<h3 id="111-インストールセットの選択">1.11 インストールセットの選択</h3>
<pre><code>Select sets by entering a set name, a file name pattern or 'all'. De-select
sets by prepending a '-'. e.g.: '-games*'. Selected sets are labeled '[X]'.
    [X] bsd           [X] base65.tgz     [X] game65.tgz    [X] xfont65.tgz
    [X] bsd.mp        [X] comp65.tgz     [X] xbase65.tgz   [X] xserv65.tgz
    [X] bsd.rd        [X] man65.tgz      [X] xshare65.tgz
Set name(s)? (or 'abort' or 'done)[done]
</code></pre><p>ここでは、インストールするセットを選択する。
例えばサーバー用途で、X Window Systemがいらない場合は、<code>-x*</code>と入力すると、X関連のインストールセットが除外される。
インストールするセットの指定がおわったら、<code>done</code>と入力するとインストールが始まる。</p>
<p>ネットワークに接続できない状態でインストールすると、</p>
<pre><code>Directory dose not contain SHA256.sig. Continue without verification? [no]
</code></pre><p>と言われるが、無い物は無いので、<code>yes</code>と回答する。</p>
<h3 id="112-タイムゾーンの設定">1.12 タイムゾーンの設定</h3>
<pre><code>What timezone are you in? [Canada/Mountain]
</code></pre><p>タイムゾーンを聞かれるので、<code>Asia/Tokyo</code>と入力する。</p>
<p>すると、</p>
<pre><code>CONGRATIRATIONS! Your OpenBSD install has been successfully completed!

When you login to your new system the first time, please read your mail
using the 'mail' command.

Exit to (S)hell, (H)alt or (R)eboot [reboot]
</code></pre><p>ひとまずインストールは成功したようだ。よかったよかった。</p>
<p>rebootを選択して再起動しよう。</p>
<h2 id="2-インストール後の設定">2. インストール後の設定</h2>
<h3 id="21-ファームウェアのインストール">2.1 ファームウェアのインストール</h3>
<h4 id="211-ファームウェアの取得">2.1.1 ファームウェアの取得</h4>
<p>インストーラーに入っていないファームウェアをインストールする。
今回は、ネットワークに接続していないので、手動でファームウェアをダウンロード・インストールする。
まず、fw_updateコマンドで不足しているファームウェアを列挙する。</p>
<pre><code># fw_update -i
Missing: inteldrm-firmware iwm-firmware vmm-firmware intel-firmware
</code></pre><p><a href="http://firmware.openbsd.org/firmware/6.5">http://firmware.openbsd.org/firmware/6.5</a> にある、不足しているファームウェアおよび、SHA256.sigをダウンロードし、
USBメモリにコピーする。</p>
<h4 id="212-usbメモリのマウント">2.1.2 USBメモリのマウント</h4>
<p>他のPCでダウンロードしたファームウェアをUSBメモリ経由でインストールするために、USBメモリをマウントする。
まずdisklabelコマンドで使用されているパーティションを調べる。</p>
<pre><code># /dev/rsd1c:
type: SCSI
disk: SCSI disk
label: USB FLASH DRIVE 
duid: 0000000000000000
flags:
bytes/sector: 512
sectors/track: 63
tracks/cylinder: 255
sectors/cylinder: 16065
cylinders: 7528
total sectors: 120938496
boundstart: 0
boundend: 120938496
drivedata: 0 

16 partitions:
#                size           offset  fstype [fsize bsize   cpg]
  c:        120938496                0  unused                    
  i:        120930432             8064   MSDOS 
</code></pre><p>どうやら<code>i</code>が、FATのパーティションのようである。</p>
<pre><code># mount /dev/sd1i /mnt
# cd /mnt
# ls
SHA256.sig                                  iwm-firmware-0.20170105.tgz
intel-firmware-20190514p0v0.tgz             vmm-firmware-1.11.0p1.tgz
inteldrm-firmware-20181218.tgz
</code></pre><p>とすると、/mntにUSBメモリがマウントされる。</p>
<h4 id="213-署名の検証">2.1.3 署名の検証</h4>
<p>ダウロードしたファイルが改竄されていないか、signifyコマンドで検証する。</p>
<pre><code># signify -C -x SHA256.sig *.tgz
Signature Verified
intel-firmware-20190514p0v0.tgz: OK
inteldrm-firmware-20181218.tgz: OK
iwm-firmware-0.20170105.tgz: OK
vmm-firmware-1.11.0p1.tgz: OK
</code></pre><p>signifyコマンドは、プリインストールされた公開鍵を使って、SHA256.sigに付されている電子署名を検証する。
その後各ファイルのSHA256ハッシュを計算し、検証することで改竄されていないことを検証することができる。</p>
<h4 id="214-ファームウェアのインストール">2.1.4 ファームウェアのインストール</h4>
<p>fw_updateコマンドに、ダウンロードしたファームウェアパッケージがあるディレクトリを指定すると
自動的にインストールしてくれる。
例えば、<code>/mnt</code>にあるならな、以下のようになる。</p>
<pre><code>fw_update -p /mnt
intel-firmware-20190514p0v0.tgz: OK
inteldrm-firmware-20181218.tgz: OK
iwm-firmware-0.20170105.tgz: OK
vmm-firmware-1.11.0p1.tgz: OK
</code></pre><p>インストールに成功したら、rebootしてファームウェアを有効にしよう。</p>
<pre><code>shutdown -r now
</code></pre><h3 id="22-システムのアップデート">2.2 システムのアップデート</h3>
<p>リリース後に公開されたパッチを適用する。</p>
<p><code>syspatch</code>コマンドを実行すると、自動で未適用のパッチを調べ、ダウンロードし、適用してくれる。</p>
<pre><code>syspatch
</code></pre><p>パッケージの更新は、</p>
<pre><code>pkg_add -u
</code></pre><p>で自動で行われる。</p>
<p>Have Fun!</p>
]]></content>
		</item>
		
		<item>
			<title>OpenBSD6.5を暗号化パーティションにインストールする方法</title>
			<link>https://www.omoikane.dev/posts/install-openbsd-in-encrypted-partition/</link>
			<pubDate>Sat, 08 Jun 2019 21:24:29 +0900</pubDate>
			
			<guid>https://www.omoikane.dev/posts/install-openbsd-in-encrypted-partition/</guid>
			<description>TLDR; OpenBSDを、暗号化パーティションにインストールすることが可能である。 インストーラー実行時に、shellに落ちて暗号化パーティションを</description>
			<content type="html"><![CDATA[<h2 id="tldr">TLDR;</h2>
<ul>
<li>
<p>OpenBSDを、暗号化パーティションにインストールすることが可能である。</p>
</li>
<li>
<p>インストーラー実行時に、shellに落ちて暗号化パーティションを作成し、そこにインストールすれば良い。</p>
</li>
</ul>
<hr>
<p>PCの盗難や紛失に備え、システムがインストールされているファイルシステムを暗号化することがある。
また、個人情報等が入ったストレージデバイスを廃棄時の事や、クラウド上のインスタンスにアタッチされているディスクは
ただのファイルであることを考えると、暗号化しておいたほうが安心だったりする。</p>
<p>OpenBSDもLinux同様、暗号化パーティションへのインストールをサポートしている。</p>
<p>以下に、OpenBSDを暗号化パーティションにインストールする方法を示す。</p>
<h2 id="1-暗号化パーティションの作成">1. 暗号化パーティションの作成</h2>
<p>OpenBSDのインストーラを起動すると、まず</p>
<pre><code>Welcome to the OpenBSD/amd64 6。5 installation program.
(I)nstall, (U)pgrade, (A)utoinstall or (S)hell?
</code></pre><p>と聞かれる。ここで<code>S</code>を選択し、Shellに落ちて暗号化パーティションを作成する。</p>
<h3 id="10-ディスク全体を乱数で埋める">1.0 ディスク全体を乱数で埋める</h3>
<p>ディスク全体を一度乱数で埋めておくと、攻撃者にディスクイメージを取得されたとしても、解析が非常に困難になる。機微な情報を保存する必要がある場合は、ディスク全体を乱数で埋めておいたほうが良い。</p>
<pre><code>dd if=/dev/urandom of=/dev/sd0 bs=1m
</code></pre><p>この処理には、非常に時間がかかる。乱数で埋める必要が無ければスキップしても問題ない。。</p>
<h3 id="uefi-or-mbr">UEFI or MBR</h3>
]]></content>
		</item>
		
		<item>
			<title>C&#43;&#43;のWeb Framework oat&#43;&#43; で Hello World</title>
			<link>https://www.omoikane.dev/posts/oat&#43;&#43;/</link>
			<pubDate>Sat, 11 May 2019 22:03:29 +0900</pubDate>
			
			<guid>https://www.omoikane.dev/posts/oat&#43;&#43;/</guid>
			<description>大きめのデータ（といっても100万点のオーダだけど）を扱うWebアプリを作りたいのだが Pythonだと遅いので、C++で書きたい。 ということ</description>
			<content type="html"><![CDATA[<p>大きめのデータ（といっても100万点のオーダだけど）を扱うWebアプリを作りたいのだが
Pythonだと遅いので、C++で書きたい。
ということで、oat++というC++で書かれたフレームワークがあったので、スケルトンコードを作成してみた。
ドキュメントもあまり詳しくなく、ちょっと苦労したので忘れないようにblogで公開しておく。</p>
<p>前述の通りoat++は、C++で書かれたWebフレームワークでパフォーマンスがべらぼうに良いらしい。
まぁネイティブコードなのでそりゃ速いよねー もちろんオープンソース。
さらに他のライブラリに依存しないのが使いやすそう。</p>
<p>oat++のWebページは、https://oatpp.io GitHubのリポジトリは、 <a href="https://github.com/oatpp/oatpp">https://github.com/oatpp/oatpp</a> である。
今回は、Debian9 stretchでコンパイル、実行を行った。</p>
<h2 id="インストール方法">インストール方法</h2>
<div class="highlight"><pre class="chroma"><code class="language-shell" data-lang="shell">sudo apt-get -y install build-essential cmake git
git clone https://github.com/oatpp/oatpp <span class="o">&amp;&amp;</span> mkdir oatpp/build
<span class="nb">cd</span> oatpp/build <span class="o">&amp;&amp;</span> cmake .. <span class="o">&amp;&amp;</span> make <span class="o">&amp;&amp;</span> sudo make install
</code></pre></div><p>必要なパッケージは、build-essentialとcmakeがあれば特にいらない。gitでcloneしてbuildするだけ。
かんたんかんたん。</p>
<h2 id="hello-world">Hello World</h2>
<p>さて、ここからが本題。
今回作成したコードは、以下の3つのファイルである。
<a href="https://github.com/oatpp/example-crud">https://github.com/oatpp/example-crud</a> を参考にした。</p>
<ul>
<li>app.cc</li>
<li>app_component.hh</li>
<li>controller.hh</li>
</ul>
<h3 id="appcc">app.cc</h3>
<div class="highlight"><pre class="chroma"><code class="language-C++" data-lang="C++"><span class="c1">//app.cc
</span><span class="c1"></span><span class="cp">#include</span> <span class="cpf">&#34;oatpp/network/server/Server.hpp&#34;</span><span class="cp">
</span><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
</span><span class="cp">#include</span> <span class="cpf">&lt;string&gt;</span><span class="cp">
</span><span class="cp">#include</span> <span class="cpf">&#34;./app_component.hh&#34;</span><span class="cp">
</span><span class="cp">#include</span> <span class="cpf">&#34;./controller.hh&#34;</span><span class="cp">
</span><span class="cp"></span>
<span class="kt">void</span> <span class="nf">run</span><span class="p">()</span> <span class="p">{</span>
        <span class="n">AppComponent</span> <span class="n">components</span><span class="p">;</span>
        <span class="k">auto</span> <span class="n">router</span> <span class="o">=</span> <span class="n">components</span><span class="p">.</span><span class="n">httpRouter</span><span class="p">.</span><span class="n">getObject</span><span class="p">();</span>
        <span class="k">auto</span> <span class="n">controller</span> <span class="o">=</span> <span class="n">Controller</span><span class="o">::</span><span class="n">createShared</span><span class="p">();</span>
        <span class="n">controller</span><span class="o">-&gt;</span><span class="n">addEndpointsToRouter</span><span class="p">(</span><span class="n">router</span><span class="p">);</span>

        <span class="n">oatpp</span><span class="o">::</span><span class="n">network</span><span class="o">::</span><span class="n">server</span><span class="o">::</span><span class="n">Server</span> <span class="n">server</span><span class="p">(</span><span class="n">components</span><span class="p">.</span><span class="n">serverConnectionProvider</span><span class="p">.</span><span class="n">getObject</span><span class="p">(),</span> <span class="n">components</span><span class="p">.</span><span class="n">serverConnectionHandler</span><span class="p">.</span><span class="n">getObject</span><span class="p">());</span>
        <span class="n">server</span><span class="p">.</span><span class="n">run</span><span class="p">();</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span> <span class="n">argv</span><span class="p">[])</span> <span class="p">{</span>
        <span class="n">oatpp</span><span class="o">::</span><span class="n">base</span><span class="o">::</span><span class="n">Environment</span><span class="o">::</span><span class="n">init</span><span class="p">();</span>
        <span class="n">run</span><span class="p">();</span>
        <span class="n">oatpp</span><span class="o">::</span><span class="n">base</span><span class="o">::</span><span class="n">Environment</span><span class="o">::</span><span class="n">destroy</span><span class="p">();</span>
        <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</code></pre></div><p>まずは、main関数が含まれるapp.cc。サーバの初期化と起動を行っている。</p>
<h3 id="app_componenthh">app_component.hh</h3>
<p>次に、app_component.hhは、app.ccのrun関数で、serverを初期化に必要なオブジェクトインスタンスを作成するクラスAppComponentを
定義している。</p>
<div class="highlight"><pre class="chroma"><code class="language-C++" data-lang="C++"><span class="c1">// app_conponent.hh
</span><span class="c1"></span><span class="cp">#pragma onece
</span><span class="cp">#include</span> <span class="cpf">&lt;string&gt;</span><span class="cp">
</span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf">&#34;oatpp/web/server/HttpConnectionHandler.hpp&#34;</span><span class="cp">
</span><span class="cp">#include</span> <span class="cpf">&#34;oatpp/web/server/HttpRouter.hpp&#34;</span><span class="cp">
</span><span class="cp">#include</span> <span class="cpf">&#34;oatpp/network/server/SimpleTCPConnectionProvider.hpp&#34;</span><span class="cp">
</span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf">&#34;oatpp/core/macro/component.hpp&#34;</span><span class="cp">
</span><span class="cp"></span>
<span class="cm">/**
</span><span class="cm"> *  Class which creates and holds Application components and registers components in oatpp::base::Environment
</span><span class="cm"> *  Order of components initialization is from top to bottom
</span><span class="cm"> */</span>
<span class="k">class</span> <span class="nc">AppComponent</span> <span class="p">{</span>
        <span class="k">private</span><span class="o">:</span>
        <span class="k">static</span> <span class="k">const</span> <span class="kt">int</span> <span class="n">PORT</span> <span class="o">=</span> <span class="mi">8000</span><span class="p">;</span>

        <span class="k">public</span><span class="o">:</span>
    
  <span class="cm">/**
</span><span class="cm">   *  Create ConnectionProvider component which listens on the port
</span><span class="cm">   */</span>
  <span class="n">OATPP_CREATE_COMPONENT</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">shared_ptr</span><span class="o">&lt;</span><span class="n">oatpp</span><span class="o">::</span><span class="n">network</span><span class="o">::</span><span class="n">ServerConnectionProvider</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">serverConnectionProvider</span><span class="p">)([]</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">oatpp</span><span class="o">::</span><span class="n">network</span><span class="o">::</span><span class="n">server</span><span class="o">::</span><span class="n">SimpleTCPConnectionProvider</span><span class="o">::</span><span class="n">createShared</span><span class="p">(</span><span class="n">PORT</span><span class="p">);</span>
  <span class="p">}());</span>
  
  <span class="cm">/**
</span><span class="cm">   *  Create Router component
</span><span class="cm">   */</span>
  <span class="n">OATPP_CREATE_COMPONENT</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">shared_ptr</span><span class="o">&lt;</span><span class="n">oatpp</span><span class="o">::</span><span class="n">web</span><span class="o">::</span><span class="n">server</span><span class="o">::</span><span class="n">HttpRouter</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">httpRouter</span><span class="p">)([]</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">oatpp</span><span class="o">::</span><span class="n">web</span><span class="o">::</span><span class="n">server</span><span class="o">::</span><span class="n">HttpRouter</span><span class="o">::</span><span class="n">createShared</span><span class="p">();</span>
  <span class="p">}());</span>
  
  <span class="cm">/**
</span><span class="cm">   *  Create ConnectionHandler component which uses Router component to route requests
</span><span class="cm">   */</span>
  <span class="n">OATPP_CREATE_COMPONENT</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">shared_ptr</span><span class="o">&lt;</span><span class="n">oatpp</span><span class="o">::</span><span class="n">network</span><span class="o">::</span><span class="n">server</span><span class="o">::</span><span class="n">HttpRouter</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">serverConnectionHandler</span><span class="p">)([]</span> <span class="p">{</span>
    <span class="n">OATPP_COMPONENT</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">shared_ptr</span><span class="o">&lt;</span><span class="n">oatpp</span><span class="o">::</span><span class="n">web</span><span class="o">::</span><span class="n">server</span><span class="o">::</span><span class="n">HttpRouter</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">router</span><span class="p">);</span> <span class="c1">// get Router component
</span><span class="c1"></span>    <span class="k">return</span> <span class="n">oatpp</span><span class="o">::</span><span class="n">web</span><span class="o">::</span><span class="n">server</span><span class="o">::</span><span class="n">HttpConnectionHandler</span><span class="o">::</span><span class="n">createShared</span><span class="p">(</span><span class="n">router</span><span class="p">);</span>
  <span class="p">}());</span>  
<span class="p">};</span>
</code></pre></div><p>OATPP_CREATE_COMPONENT マクロは、oatpp/core/macro/component.hpp で以下のように定義されている。</p>
<div class="highlight"><pre class="chroma"><code class="language-C++" data-lang="C++"><span class="cp">#define OATPP_CREATE_COMPONENT(TYPE, NAME) \
</span><span class="cp">oatpp::base::Environment::Component&lt;TYPE&gt; NAME = oatpp::base::Environment::Component&lt;TYPE&gt;
</span></code></pre></div><p>変数を宣言しているだけでした。</p>
<p>このクラスでは、ServerConnectionProvider、HttpRouter、HttpConnectionHandlerを作成している。</p>
<h3 id="controllerhh">controller.hh</h3>
<p>そして、controller.hhでは、URLマッピングと呼ばれたときの処理を記述する、Controllerクラスを定義している。</p>
<div class="highlight"><pre class="chroma"><code class="language-C++" data-lang="C++"><span class="c1">//controller.hh
</span><span class="c1"></span><span class="cp">#pragma onece
</span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf">&#34;oatpp/web/server/api/ApiController.hpp&#34;</span><span class="cp">
</span><span class="cp">#include</span> <span class="cpf">&#34;oatpp/parser/json/mapping/ObjectMapper.hpp&#34;</span><span class="cp">
</span><span class="cp">#include</span> <span class="cpf">&#34;oatpp/core/macro/codegen.hpp&#34;</span><span class="cp">
</span><span class="cp">#include</span> <span class="cpf">&#34;oatpp/core/macro/component.hpp&#34;</span><span class="cp">
</span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf">&lt;sstream&gt;</span><span class="cp">
</span><span class="cp"></span>
<span class="k">class</span> <span class="nc">Controller</span> <span class="o">:</span> <span class="k">public</span> <span class="n">oatpp</span><span class="o">::</span><span class="n">web</span><span class="o">::</span><span class="n">server</span><span class="o">::</span><span class="n">api</span><span class="o">::</span><span class="n">ApiController</span> <span class="p">{</span>
<span class="k">public</span><span class="o">:</span>
        <span class="n">Controller</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">shared_ptr</span><span class="o">&lt;</span><span class="n">ObjectMapper</span><span class="o">&gt;&amp;</span> <span class="n">objectMapper</span><span class="p">)</span>
                <span class="o">:</span> <span class="n">oatpp</span><span class="o">::</span><span class="n">web</span><span class="o">::</span><span class="n">server</span><span class="o">::</span><span class="n">api</span><span class="o">::</span><span class="n">ApiController</span><span class="p">(</span><span class="n">objectMapper</span><span class="p">)</span>
        <span class="p">{}</span>

        <span class="k">static</span> <span class="n">std</span><span class="o">::</span><span class="n">shared_ptr</span><span class="o">&lt;</span><span class="n">Controller</span><span class="o">&gt;</span> <span class="n">createShared</span><span class="p">(</span><span class="n">OATPP_COMPONENT</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">shared_ptr</span><span class="o">&lt;</span><span class="n">ObjectMapper</span><span class="o">&gt;</span><span class="p">,</span><span class="n">objectMapper</span><span class="p">))</span>
        <span class="p">{</span>
            <span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">make_shared</span><span class="o">&lt;</span><span class="n">Controller</span><span class="o">&gt;</span><span class="p">(</span><span class="n">objectMapper</span><span class="p">);</span>
        <span class="p">}</span>


<span class="cp">#include</span> <span class="cpf">OATPP_CODEGEN_BEGIN(ApiController)</span><span class="cp">
</span><span class="cp"></span>
<span class="n">ENDPOINT</span><span class="p">(</span><span class="s">&#34;GET&#34;</span><span class="p">,</span> <span class="s">&#34;/&#34;</span><span class="p">,</span> <span class="n">root</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">html</span> <span class="o">=</span>
    <span class="s">&#34;&lt;html lang=&#39;en&#39;&gt;&#34;</span>
    <span class="s">&#34;&lt;head&gt;&#34;</span>
    <span class="s">&#34;&lt;meta charset=utf-8/&gt;&#34;</span>
    <span class="s">&#34;&lt;/head&gt;&#34;</span>
    <span class="s">&#34;&lt;body&gt;&#34;</span>
    <span class="s">&#34;&lt;p&gt;Hello World&lt;/p&gt;&#34;</span>
    <span class="s">&#34;&lt;/body&gt;&#34;</span>
    <span class="s">&#34;&lt;/html&gt;&#34;</span><span class="p">;</span>
    <span class="k">auto</span> <span class="n">response</span> <span class="o">=</span> <span class="n">createResponse</span><span class="p">(</span><span class="n">Status</span><span class="o">::</span><span class="n">CODE_200</span><span class="p">,</span> <span class="n">html</span><span class="p">);</span>
    <span class="n">response</span><span class="o">-&gt;</span><span class="n">putHeader</span><span class="p">(</span><span class="n">Header</span><span class="o">::</span><span class="n">CONTENT_TYPE</span><span class="p">,</span> <span class="s">&#34;text/html&#34;</span><span class="p">);</span>
    <span class="k">return</span> <span class="n">response</span><span class="p">;</span>
<span class="p">}</span>

<span class="n">ENDPOINT</span><span class="p">(</span><span class="s">&#34;GET&#34;</span><span class="p">,</span> <span class="s">&#34;/get&#34;</span><span class="p">,</span> <span class="n">get_test</span><span class="p">,</span> <span class="n">REQUEST</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">shared_ptr</span><span class="o">&lt;</span><span class="n">IncomingRequest</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">request</span><span class="p">)</span>
<span class="p">)</span>
<span class="p">{</span>
    <span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">resp</span> <span class="o">=</span> <span class="p">(</span><span class="n">request</span><span class="o">-&gt;</span><span class="n">getQueryParameter</span><span class="p">(</span><span class="s">&#34;name&#34;</span><span class="p">,</span> <span class="s">&#34;&#34;</span><span class="p">))</span><span class="o">-&gt;</span><span class="n">c_str</span><span class="p">();</span>

    <span class="k">auto</span> <span class="n">response</span> <span class="o">=</span> <span class="n">createResponse</span><span class="p">(</span><span class="n">Status</span><span class="o">::</span><span class="n">CODE_200</span><span class="p">,</span> <span class="n">resp</span><span class="p">);</span>
    <span class="n">response</span><span class="o">-&gt;</span><span class="n">putHeader</span><span class="p">(</span><span class="n">Header</span><span class="o">::</span><span class="n">CONTENT_TYPE</span><span class="p">,</span> <span class="s">&#34;text/plain&#34;</span><span class="p">);</span>
    <span class="k">return</span> <span class="n">response</span><span class="p">;</span>
<span class="p">}</span>


<span class="n">ENDPOINT</span><span class="p">(</span><span class="s">&#34;POST&#34;</span><span class="p">,</span> <span class="s">&#34;/post&#34;</span><span class="p">,</span> <span class="n">post_test</span><span class="p">,</span> <span class="n">BODY_STRING</span><span class="p">(</span><span class="n">String</span><span class="p">,</span> <span class="n">request</span><span class="p">)</span>
<span class="p">)</span>
<span class="p">{</span>
    <span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">resp</span> <span class="o">=</span> <span class="n">request</span><span class="o">-&gt;</span><span class="n">c_str</span><span class="p">();</span>

    <span class="k">auto</span> <span class="n">response</span> <span class="o">=</span> <span class="n">createResponse</span><span class="p">(</span><span class="n">Status</span><span class="o">::</span><span class="n">CODE_200</span><span class="p">,</span> <span class="n">resp</span><span class="p">);</span>
    <span class="n">response</span><span class="o">-&gt;</span><span class="n">putHeader</span><span class="p">(</span><span class="n">Header</span><span class="o">::</span><span class="n">CONTENT_TYPE</span><span class="p">,</span> <span class="s">&#34;text/plain&#34;</span><span class="p">);</span>
    <span class="k">return</span> <span class="n">response</span><span class="p">;</span>
<span class="p">}</span>


<span class="n">ENDPOINT</span><span class="p">(</span><span class="s">&#34;GET&#34;</span><span class="p">,</span> <span class="s">&#34;/query-test&#34;</span><span class="p">,</span> <span class="n">query_test</span><span class="p">,</span> 
        <span class="n">QUERY</span><span class="p">(</span><span class="n">String</span><span class="p">,</span> <span class="n">p</span><span class="p">,</span> <span class="s">&#34;lon&#34;</span><span class="p">),</span> <span class="n">QUERY</span><span class="p">(</span><span class="n">Float64</span><span class="p">,</span> <span class="n">q</span><span class="p">,</span> <span class="s">&#34;lat&#34;</span><span class="p">)</span>
<span class="p">)</span>
<span class="p">{</span>
        <span class="n">std</span><span class="o">::</span><span class="n">stringstream</span> <span class="n">resp</span><span class="p">;</span>
        <span class="n">resp</span><span class="o">&lt;&lt;</span> <span class="s">&#34;p=&#34;</span><span class="o">&lt;&lt;</span><span class="n">p</span><span class="o">-&gt;</span><span class="n">c_str</span><span class="p">()</span><span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span>
                <span class="o">&lt;&lt;</span> <span class="s">&#34;q=&#34;</span><span class="o">&lt;&lt;</span><span class="n">q</span><span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>

    <span class="k">auto</span> <span class="n">response</span> <span class="o">=</span> <span class="n">createResponse</span><span class="p">(</span><span class="n">Status</span><span class="o">::</span><span class="n">CODE_200</span><span class="p">,</span> <span class="n">resp</span><span class="p">.</span><span class="n">str</span><span class="p">().</span><span class="n">c_str</span><span class="p">());</span>
    <span class="n">response</span><span class="o">-&gt;</span><span class="n">putHeader</span><span class="p">(</span><span class="n">Header</span><span class="o">::</span><span class="n">CONTENT_TYPE</span><span class="p">,</span> <span class="s">&#34;text/plain&#34;</span><span class="p">);</span>
    <span class="k">return</span> <span class="n">response</span><span class="p">;</span>
<span class="p">}</span>


<span class="n">ENDPOINT</span><span class="p">(</span><span class="s">&#34;GET&#34;</span><span class="p">,</span> <span class="s">&#34;/tile/${z}/${x}/${y}&#34;</span><span class="p">,</span> <span class="n">path_test</span><span class="p">,</span> 
        <span class="n">PATH</span><span class="p">(</span><span class="n">Int32</span><span class="p">,</span> <span class="n">z</span><span class="p">),</span> <span class="n">PATH</span><span class="p">(</span><span class="n">Int32</span><span class="p">,</span> <span class="n">x</span><span class="p">),</span> <span class="n">PATH</span><span class="p">(</span><span class="n">Int32</span><span class="p">,</span> <span class="n">y</span><span class="p">),</span> <span class="n">HEADER</span><span class="p">(</span><span class="n">Int32</span><span class="p">,</span> <span class="n">param</span><span class="p">))</span>
<span class="p">{</span>
        <span class="n">std</span><span class="o">::</span><span class="n">stringstream</span> <span class="n">resp</span><span class="p">;</span>
        <span class="n">resp</span><span class="o">&lt;&lt;</span> <span class="s">&#34;zoomlevel = &#34;</span><span class="o">&lt;&lt;</span> <span class="n">z</span><span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span>
                <span class="o">&lt;&lt;</span> <span class="s">&#34;x = &#34;</span><span class="o">&lt;&lt;</span> <span class="n">x</span><span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span>
                <span class="o">&lt;&lt;</span> <span class="s">&#34;y = &#34;</span><span class="o">&lt;&lt;</span> <span class="n">y</span><span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span>
                <span class="o">&lt;&lt;</span> <span class="s">&#34;param = &#34;</span><span class="o">&lt;&lt;</span> <span class="n">param</span><span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>

    <span class="k">auto</span> <span class="n">response</span> <span class="o">=</span> <span class="n">createResponse</span><span class="p">(</span><span class="n">Status</span><span class="o">::</span><span class="n">CODE_200</span><span class="p">,</span> <span class="n">resp</span><span class="p">.</span><span class="n">str</span><span class="p">().</span><span class="n">c_str</span><span class="p">());</span>
    <span class="n">response</span><span class="o">-&gt;</span><span class="n">putHeader</span><span class="p">(</span><span class="n">Header</span><span class="o">::</span><span class="n">CONTENT_TYPE</span><span class="p">,</span> <span class="s">&#34;text/plain&#34;</span><span class="p">);</span>
    <span class="k">return</span> <span class="n">response</span><span class="p">;</span>
<span class="p">}</span>



<span class="cp">#include</span> <span class="cpf">OATPP_CODEGEN_END(ApiController)</span><span class="cp">
</span><span class="cp"></span><span class="p">};</span>
</code></pre></div><p>各、URLマッピングは、ENDPOINTマクロを使用する。
ENDPOINTマクロは、OATPP_CODEGEN_BEGIN()と、OATPP_CODEGEN_END()で囲む。
<code>#include OATPP_CODEGEN_BEGIN(ApiController)</code>は、<code>#include oatpp/codegen/codegen_define_ApiController_.hpp</code>に展開される。
oatpp/codegen_define_ApiController_.hppでは、ENDPOINTマクロで使用するマクロ類が宣言されている。</p>
<p>ENDPOINTマクロは、見てわかるように、<code>#define ENDPOINT(METHOD, PATH, NAME, ...)</code>と宣言されており、
oatpp::web::protocol::http::outgoing::Response を返す関数に展開される。
4番目以降のパラメータは、パラメータマッピングで、関数での処理に必要なリクエストパラメータを指定する。</p>
<h4 id="parameter-mapping">Parameter Mapping</h4>
<p>oat++には、以下のパラメータマッピングがある</p>
<ul>
<li>ヘッダ</li>
</ul>
<pre><code>HEADER(&lt;data-type&gt;, &lt;param-name&gt;, &quot;&lt;optional header-name&gt;&quot;)
</code></pre><ul>
<li>パス</li>
</ul>
<pre><code>PATH(&lt;data-type&gt;, &lt;param-name&gt;, &quot;&lt;optional path-variable-name&gt;&quot;)
</code></pre><ul>
<li>クエリ</li>
</ul>
<pre><code>QUERY(&lt;data-type&gt;, &lt;param-name&gt;, &quot;&lt;optional path-variable-name&gt;&quot;)
</code></pre><ul>
<li>Body</li>
</ul>
<pre><code>BODY_STRING(String, &lt;param-name&gt;)
</code></pre><ul>
<li>リクエスト</li>
</ul>
<pre><code>REQUEST(std::shared_ptr&lt;IncomingRequest&gt;, request)
</code></pre><ul>
<li>DTO</li>
</ul>
<pre><code>BODY_DTO(&lt;DTO-class&gt;::ObjectWrapper, &lt;param-name&gt;)
</code></pre><p>パラメータマッピングは、https://oatpp.io/docs/components/api-controller/ にドキュメントがあるが、
正直、どう書くのかほとんどわからなかった。
前掲の<code>controller.hh</code>がサンプルになっていると思う。</p>
<p>data-typeは、以下の型が使えることを確認した。Booleanも使えるかも。</p>
<ul>
<li>String</li>
<li>Int32</li>
<li>Int64</li>
<li>Float32</li>
<li>Float64</li>
</ul>
<h2 id="makefile">Makefile</h2>
<p>一応、Makefileも。</p>
<div class="highlight"><pre class="chroma"><code class="language-Makefile" data-lang="Makefile"><span class="nv">CXX</span><span class="o">=</span>g++
<span class="nv">CXXFLAGS</span><span class="o">=</span>-I /usr/local/include/oatpp-0.19.4/oatpp --std<span class="o">=</span>c++11 -w -Wall
<span class="nv">LDFLAGS</span><span class="o">=</span>-L /usr/local/lib/oatpp-0.19.4/ -loatpp -loatpp-test -lpthread

<span class="nf">all</span><span class="o">:</span> <span class="n">app</span>

<span class="nf">.o</span><span class="o">:</span>.<span class="n">cc</span>
        <span class="k">$(</span>CXX<span class="k">)</span> -c <span class="k">$(</span>CXXFLAGS<span class="k">)</span> $&lt;

<span class="nf">app</span><span class="o">:</span> <span class="n">app</span>.<span class="n">o</span> 
        <span class="k">$(</span>CXX<span class="k">)</span>  -o <span class="nv">$@</span> $&lt; <span class="k">$(</span>LDFLAGS<span class="k">)</span>

<span class="nf">app.o</span><span class="o">:</span> <span class="n">app</span>.<span class="n">cc</span> <span class="n">app_component</span>.<span class="n">hh</span>

<span class="nf">clean</span><span class="o">:</span>
        rm -f app *.o
</code></pre></div><p>Have Fan!</p>
]]></content>
		</item>
		
		<item>
			<title>OpenBSD6.4をインストールしたVPSでIPv6を使う際の注意</title>
			<link>https://www.omoikane.dev/posts/openbsd-ipv6-sakura/</link>
			<pubDate>Wed, 17 Apr 2019 23:03:29 +0900</pubDate>
			
			<guid>https://www.omoikane.dev/posts/openbsd-ipv6-sakura/</guid>
			<description>TL;DR OpenBSD 6.4をインストールしたVPSでIPv6のデフォルトゲートウェイに接続できない時は、 SIIを無効にすること。例えば、さくらインターネット</description>
			<content type="html"><![CDATA[<h2 id="tldr">TL;DR</h2>
<p>OpenBSD 6.4をインストールしたVPSでIPv6のデフォルトゲートウェイに接続できない時は、
SIIを無効にすること。例えば、さくらインターネットの場合、hostname.vio0は以下のようになる。</p>
<pre><code>inet  203.0.113.23 255.255.254.0
inet6 autoconf -autoconfprivacy -soii
inet6 alias 2001:db8:102:3013:203:0:113:23 64
up
!route -nq add -inet6 default fe80::1%vio0
</code></pre><hr>
<p>OpenBSDをインストールしたさくらVPSのインスタンスでIPv6の
デフォルトゲートウェイと通信できなくてハマった。
なんとか解決できたのでメモ。</p>
<p>さくらVPSは、グローバルIPv6のIPを一つくれる。
そのゲートウェイはfe80::1である。</p>
<p>OpenBSD 6.3あたりから、Semantically Opaque Interface Identifiers (SOIIs) がデフォルトで有効になっている。
SOIIとはSLAACアドレス（自動で設定されるリンクローカルアドレス）のインターフェース識別子(IID)にMACアドレスを使わずに、
プレフィックスも使ってIIDを生成することで、リングローカルアドレスを生成するというもの（RFC7217）。</p>
<p>以前は、MACアドレスだけからリンクローカルアドレスを生成していた（Modified EUI-64）ため、プレフィックスが変化しても
リンクローカルアドレスから容易にMACアドレスが特定でき、プライバシーやセキュリティの問題があった。
OpenBSDはそれをいやがって、SOIIをデフォルトで有効にしたのだろう。</p>
<p>一方、さくらのゲートウェイは、IIDをMACアドレスから生成する昔ながらのModified EUI-64を前提にフィルタリングしている
と思われる。そのため、SOIIで生成されたアドレスはフィルターされIPv6でインターネットに接続できなかったのだろう。</p>
<p>SIIを無効にするには、上記の例のように、ifconfigのオプションに、-soiiをつける。詳細は、ifconfigのmanページを参照のこと。</p>
]]></content>
		</item>
		
		<item>
			<title>blog restart</title>
			<link>https://www.omoikane.dev/posts/restart/</link>
			<pubDate>Wed, 17 Apr 2019 22:30:18 +0900</pubDate>
			
			<guid>https://www.omoikane.dev/posts/restart/</guid>
			<description>操作ミスで、メールサーバやらWebサーバをホストしていたさくらのVPSを飛ばしてしまったので、 ドメインも変えてやりなおすことにしました。 この</description>
			<content type="html"><![CDATA[<p>操作ミスで、メールサーバやらWebサーバをホストしていたさくらのVPSを飛ばしてしまったので、
ドメインも変えてやりなおすことにしました。</p>
<p>このblogはガチ技術よりにしようかと思っています。どうぞよろしくお願いします。</p>
]]></content>
		</item>
		
	</channel>
</rss>
