備忘録

備忘録

.NET Coreで実行ファイル1つだけを出力する方法(Warpを利用する場合)(非推奨)

Ⅰ. はじめに

タイトルの通り「.NET Coreで実行ファイル1つだけを出力する方法(Warpを利用する場合)(非推奨)」です。

「.NET Core で 実行ファイル(.exe)を作成する方法」はこちら
https://kagasu.hatenablog.com/entry/2017/04/16/192117

「.NET Coreで実行ファイル1つだけを出力する方法」はこちら
※特に理由がない限りこちらを利用して下さい。
https://kagasu.hatenablog.com/entry/2019/05/08/022255

SCD(Self-contained deployments) を行うと「実行ファイル1つだけ」ではなく、「実行ファイル1つと100個を超えるDLLファイル」が同時に出力されます。
100個を超えるDLLファイルは CoreCLR と呼ばれる .NET Core のランタイムなので削除できません。

その為この記事では「フォルダを圧縮して1つの実行ファイルに埋め込む」事ができる Warp を利用する方法を紹介します。

※2019/05/08 追記
.NET Core 3.0で PublishSingleFile が追加されました。
よって、Warpを利用する方法を非推奨に変更しました。

Ⅱ. Warp とは

.NET Core, Node.js 等に対応した自己展開ファイルを作成する為のアプリケーションです。
実行時に一時ディレクトリに自己展開する為、起動速度以外のパフォーマンスは低下しません。

https://github.com/dgiagio/warp

Ⅲ. やり方

1. 以下記事を参考にしてSCDを行う

https://kagasu.hatenablog.com/entry/2017/04/16/192117

2. Warp をダウンロードする

https://github.com/dgiagio/warp/releases

3. Warp で自己展開ファイルを作成する

WindowsLinux向けファイルを作成する事もできます。

# Windows
warp-packer --arch windows-x64 --input_dir bin/Release/netcoreapp2.1/win-x64/publish --exec myapp.exe --output out.exe

# Linux
warp-packer --arch linux-x64 --input_dir bin/Release/netcoreapp2.1/linux-x64/publish --exec myapp --output out

# macOS
warp-packer --arch macos-x64 --input_dir bin/Release/netcoreapp2.1/osx-x64/publish --exec myapp --output out
4. 実行結果

f:id:kagasu:20181211021547p:plain

Laravel MixのJavaScriptを難読化する方法

w* Ⅰ. はじめに
タイトルの通り「Laravel MixのJavaScriptを難読化する方法」です。
javascript-obfuscator の webpackプラグインである webpack-obfuscator を利用した方法をこの記事で紹介します。

Ⅱ. やり方

1. webpack-obfuscator をインストールする
npm install --save-dev webpack-obfuscator@2.6.0
2. webpack.mix.js を編集する
let mix = require('laravel-mix')

// 以下を追加
let JavaScriptObfuscator = require('webpack-obfuscator')

let config = {}

if (mix.inProduction()) {
  config.plugins = [
    new JavaScriptObfuscator({
      stringArray: true,
      stringArrayEncoding: [ 'rc4' ],
      stringArrayThreshold: 1,
      transformObjectKeys: true,
      // debugProtection: true,
      // domainLock: [ '.example.com' ],
      // renameProperties: true // プロパティ名を変更する。利用は留意する必要がある
    })
  ]
}

mix.webpackConfig(config)
// ここまで

mix.js('resources/assets/js/app.js', 'public/js')
  .sass('resources/assets/sass/app.scss', 'public/css').version()
3. ビルドする
npm run production

実行結果


Ⅲ. やり方2(uglify を無効にして難読化する方法)

webpack.mix.js

if (mix.inProduction()) {
  mix.options({
    uglify: false
  })

  config.plugins = [
    new JavaScriptObfuscator({
      rotateUnicodeArray: true,
      compact: true,
    })
  ]
}

KotlinでAES/ZeroPaddingで暗号化と複合する方法

Ⅰ. はじめに

タイトルの通り「KotlinでAES/ZeroPaddingで暗号化と複合する方法」です。

Ⅱ. サンプルプログラム

import org.dom4j.io.SAXReader
import java.io.File
import java.io.FileWriter
import javax.crypto.spec.SecretKeySpec
import javax.crypto.Cipher
import java.util.*
import javax.crypto.spec.IvParameterSpec

fun byteArrayOfInts(vararg ints: Int) = ByteArray(ints.size) { pos -> ints[pos].toByte() }

fun concatByteArray(array1: ByteArray, array2: ByteArray): ByteArray {
  val newArray = ByteArray(array1.size + array2.size)
  System.arraycopy(array1, 0, newArray, 0, array1.size)
  System.arraycopy(array2, 0, newArray, array1.size, array2.size)
  return newArray
}

fun encrypt(key: ByteArray, iv: ByteArray, str: String): String {
  val cipher = Cipher.getInstance("AES/CBC/NoPadding")
  val secretKeySpec = SecretKeySpec(key, "AES")
  val ivParameterSpec = IvParameterSpec(iv)
  cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec)
  var bytes = str.toByteArray()
  if (bytes.size % 16 != 0) {
    val paddingBytes = ByteArray(16 - (bytes.size % 16))
    bytes = concatByteArray(bytes, paddingBytes)
  }

  return Base64.getEncoder().encodeToString(cipher.doFinal(bytes))
}

fun decrypt(key: ByteArray, iv: ByteArray, str: String): String {
  val cipher = Cipher.getInstance("AES/CBC/NoPadding")
  val secretKeySpec = SecretKeySpec(key, "AES")
  val ivParameterSpec = IvParameterSpec(iv)
  cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec)
  var bytes = Base64.getDecoder().decode(str)
  bytes = cipher.doFinal(bytes)

  var paddingCount = 0
  for (i in bytes.size - 1 downTo 0) {
    if (bytes[i].toInt() == 0) {
      paddingCount++
    } else {
      break
    }
  }

  val newArray = ByteArray(bytes.size - paddingCount)
  System.arraycopy(bytes, 0, newArray, 0, bytes.size - paddingCount)
  return String(newArray)
}

fun main(args: Array<String>) {
  val key = "4b865d387f4a434da70d17a258976a9c".toByteArray()
  val iv = byteArrayOfInts(0x2f, 0x15, 0x25, 0x50, 0x51, 0xAD, 0xEB, 0xCB, 0x01, 0x60, 0x16, 0x32, 0x56, 0xBB, 0x12, 0xDD)
  val str = encrypt(key, iv, "Hello World!")
  println("$str")
  println("${decrypt(key, iv, str)}")
}

実行結果

0NmDTGCeDKGbhbQt/ltnaw==
Hello World!

KotlinでXMLファイルの読み込み、書き込みを行う方法

Ⅰ. はじめに

タイトルの通り「KotlinでXMLファイルの読み込み、書き込みを行う方法」です。

この記事でサンプルとして利用するXMLファイルは以下の通りです。
input.xml

<?xml version='1.0' encoding='utf-8' standalone='no' ?>
<map>
    <string name="name001">value001</string>
    <string name="name002">value002</string>
    <string name="name003">value003</string>
</map>

Ⅱ. dom4j を利用する方法

サンプルプログラム

build.gradle

dependencies {
  compile 'jaxen:jaxen:1.1.6'
  compile 'org.dom4j:dom4j:2.1.1'
}

Main.kt

import org.dom4j.io.SAXReader
import java.io.File
import java.io.FileWriter

fun main(args: Array<String>) {
  val document = SAXReader().read(File("input.xml"))
  val nodes = document.selectNodes("/map/string")
  for (node in nodes) {
    println("${node.name}, ${node.valueOf("@name")}, ${node.stringValue}")

    node.text = "123"
  }

  val writer = FileWriter("out.xml")
  document.write(writer)
  writer.close()
}

実行結果

string, name001, value001
string, name002, value002
string, name003, value003

out.xml

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<map>
    <string name="name001">123</string>
    <string name="name002">123</string>
    <string name="name003">123</string>
</map>

Ⅲ. javax.xml を利用した方法

サンプルプログラム

Main.kt

import org.w3c.dom.NodeList
import java.io.File
import java.io.StringWriter
import javax.xml.parsers.DocumentBuilderFactory
import javax.xml.transform.TransformerFactory
import javax.xml.transform.dom.DOMSource
import javax.xml.transform.stream.StreamResult
import javax.xml.xpath.XPathConstants
import javax.xml.xpath.XPathFactory

fun main(args: Array<String>) {

  val documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder()
  val document = documentBuilder.parse(File("input.xml"))

  val xPath = XPathFactory.newInstance().newXPath()
  val nodes = xPath.evaluate("/map/string", document, XPathConstants.NODESET) as NodeList

  for (i in 0 until nodes.length) {
    val node = nodes.item(i)
    val nameAttributeValue = node.attributes.getNamedItem("name").nodeValue

    println("${node.nodeName}, $nameAttributeValue, ${node.textContent}")
    node.textContent = "123"
  }

  // write
  val writer = StringWriter()
  val transformer = TransformerFactory.newInstance().newTransformer()
  transformer.transform(DOMSource(document), StreamResult(writer))
  File("out.xml").writeText(writer.toString())
}

実行結果

string, name001, value001
string, name002, value002
string, name003, value003

out.xml

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<map>
    <string name="name001">123</string>
    <string name="name002">123</string>
    <string name="name003">123</string>
</map>