1

plain text:Hello leon

password & iv:leon1234leon1234

cipher: rijndael cbc 128bits

nppcrypto encrypt info

<nppcrypt version="1016">
<encryption cipher="rijndael" key-length="16" mode="cbc" encoding="base64" />
<key algorithm="scrypt" N="16384" r="8" p="1" salt="HA==" />
<iv value="bGVvbjEyMzRsZW9uMTIzNA==" method="custom" />
</nppcrypt>
/8r4DGLVYC+YJSPMFQ8lFQ==

I use java BouncyCastle lib to test, but the encrypt result is diffent

related code is at my github repo

https://github.com/Leon406/Crypto/blob/master/src/main/kotlin/me/leon/modern/PBE.kt

nppcrypt plugin repo: https://github.com/jeanpaulrichter/nppcrypt

Edit: code here as well

package me.leon.modern

import com.lambdaworks.crypto.SCryptUtil
import me.leon.base64Decode
import me.leon.toBase64
import org.bouncycastle.crypto.generators.BCrypt
import org.bouncycastle.crypto.generators.KDF2BytesGenerator
import org.bouncycastle.crypto.generators.SCrypt
import org.bouncycastle.util.encoders.Hex

/**
 *
 *
 * https://www.bouncycastle.org/specifications.html
 * https://antofthy.gitlab.io/info/crypto/key_derivation.txt
 * https://www.openssl.org/docs/manmaster/man1/openssl-kdf.html
 * key derivation function
 * SCrypt   BCrypt  PBKDF2    Added in OpenSSL 3.0
 * Question? how to interact notepad++ nppcrypto
 */
object PBE {
    @JvmStatic
    fun main(args: Array<String>) {
        val pwd = "leon1234leon1234"
        val salt = "HA=="
        val ivbase64 = "leon1234leon1234"
        val key = SCrypt.generate(pwd.toByteArray(), salt.base64Decode(), 16384, 8, 1, 16).toBase64()
        val key2 = BCrypt.generate(pwd.toByteArray(), "iP/MuFEP/jgHs7lBGez7kg==".base64Decode(), 8).toBase64()
        println(key)

        SCryptUtil.scrypt(pwd,16384,8,1).also {
            println("scrypt $it")
        }
        //$s0$e0801$YzXui6dcQ0qbWnTBP36t+Q==$AW81b69h3HepUIi7pW7ThAKuDdpb1oZ7bFIJrF9zQzA=
        //$s0$e0801$bGvjR0//WiaHqAiSDi5Q9g==$8DzAr+nhUyW5fhdj3MLIpovRdp+dLfVoXGqN+Pp3kZU=
         SCrypt.generate(pwd.toByteArray(), "YzXui6dcQ0qbWnTBP36t+Q==".base64Decode(), 16384, 8, 1, 32).toBase64().also {
             println("scrypt dd $it" )
         }
        val r = SymmetricCrypto.encrypt(key, "Hello leon", ivbase64, "AES/CBC/PKCS5Padding")
            .also { println(it) }
        val r2 = SymmetricCrypto.encrypt(key2, "Hello leon", ivbase64, "AES/CBC/PKCS5Padding")
            .also { println(it) }

        SymmetricCrypto.decrypt(key, r, ivbase64, "AES/CBC/PKCS5Padding").also { println(it) }
        SymmetricCrypto.decrypt(key2, r2, ivbase64, "AES/CBC/PKCS5Padding").also { println(it) }
    }
}
Michael Fehr
  • 5,827
  • 2
  • 19
  • 40
Leon
  • 11
  • 2

1 Answers1

0

You pass the key to SymmetricCrypto.decrypt() Base64 encoded, but you do not perform Base64 decoding there, but UTF8 encoding, s. here. For this reason the decryption fails.

Usually key and IV are binary data and not a string. Therefore both should be passed as ByteArray in encrypt()/decrypt(). If they are to be passed as a string, then a reliable binary-to-text encoding must be performed, such as Base64.

The following fix uses the second variant, i.e. passes to decrypt() a Base64 encoded key and IV and Base64 decodes both there:

import org.bouncycastle.crypto.generators.SCrypt
import org.bouncycastle.jce.provider.BouncyCastleProvider
import java.security.Security
import java.util.*
import javax.crypto.Cipher
import javax.crypto.SecretKey
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.SecretKeySpec
...
val pwd = "leon1234leon1234"
val salt = "HA=="
val key = SCrypt.generate(pwd.toByteArray(), salt.base64Decode(), 16384, 8, 1, 16).toBase64().also { println(it) } // 6owLoTdeL67pEHxJ5gLY9Q==
val iv = "bGVvbjEyMzRsZW9uMTIzNA=="
val ciphertext = "/8r4DGLVYC+YJSPMFQ8lFQ=="
/*SymmetricCrypto.*/decrypt(key, ciphertext, iv, "AES/CBC/PKCS5Padding").also { println(it) } // Hello leon
...
fun decrypt(key: String, data: String, iv: String, alg: String): String {
    val cipher = Cipher.getInstance(alg)
    val keySpec: SecretKey = SecretKeySpec(key.base64Decode()/*toByteArray()*/, alg.substringBefore("/")) // pass key Base64 encoded and Base64 decode here
    if (alg.contains("ECB".toRegex()))
        cipher.init(Cipher.DECRYPT_MODE, keySpec)
    else
        cipher.init(Cipher.DECRYPT_MODE, keySpec, IvParameterSpec(iv.base64Decode()/*toByteArray()*/)) // pass iv Base64 encoded and Base64 decode here
    return String(cipher.doFinal(Base64.getDecoder().decode(data)))
}

A few notes concerning security:

  • Static IVs are insecure. nppcrypt supports random IVs. The IV should not be identical to the password.
  • A 1 byte salt is too short.
  • ECB is insecure (just for completeness, since ECB is not used in the posted example, but is implemented).
Topaco
  • 40,594
  • 4
  • 35
  • 62
  • The demo I wrote can decrypt sucessfully.The Question is why the answer it not the same as notepad++ plugin encryted – Leon Jun 15 '21 at 02:37
  • I forget change ivbase64 name, it's not base64 encoded, and it indeed misleads you – Leon Jun 15 '21 at 02:50