Skip to content

Instantly share code, notes, and snippets.

@satorg
Last active September 22, 2020 06:45
Show Gist options
  • Save satorg/b92b978015efbbfd70b5cad349c396a6 to your computer and use it in GitHub Desktop.
Save satorg/b92b978015efbbfd70b5cad349c396a6 to your computer and use it in GitHub Desktop.
Simple Password Based Encryptor/Decryptor
import java.nio.ByteBuffer
import java.security.{Key, SecureRandom}
import javax.crypto.spec.{IvParameterSpec, PBEKeySpec, SecretKeySpec}
import javax.crypto.{Cipher, SecretKeyFactory}
import scala.util.chaining._
class SPBCryptor(iterationCount: Int = SPBCryptor.DefaultIterationCount) {
import SPBCryptor._
def createKey(password: Array[Char], salt: Array[Byte]): Key = {
new PBEKeySpec(password, salt, iterationCount, KeyLength)
.pipe { mkSecretKeyFactory.generateSecret }
.getEncoded
.pipe { mkSecretKeySpec }
}
def encrypt(password: Array[Char], message: Array[Byte], saltSize: Int = DefaultSaltSize): Array[Byte] = {
val salt = new Array[Byte](saltSize).tap { mkSecureRandom.nextBytes }
val (iv, encrypted) =
mkCipher
.tap {
_.init(
Cipher.ENCRYPT_MODE,
createKey(password, salt))
}
.pipe { cipher =>
(cipher.getIV, cipher.doFinal(message))
}
ByteBuffer
.allocate(Integer.BYTES + salt.length + Integer.BYTES + iv.length + encrypted.length)
.putInt(salt.length).put(salt)
.putInt(iv.length).put(iv)
.put(encrypted)
.array()
}
def decrypt(password: Array[Char], message: Array[Byte]): Array[Byte] = {
val (salt, iv, encrypted) =
ByteBuffer.wrap(message).pipe { buffer =>
(
new Array[Byte](buffer.getInt()).tap { buffer.get },
new Array[Byte](buffer.getInt()).tap { buffer.get },
new Array[Byte](buffer.remaining()).tap { buffer.get }
)
}
mkCipher
.tap {
_.init(
Cipher.DECRYPT_MODE,
createKey(password, salt),
new IvParameterSpec(iv)
)
}
.doFinal(encrypted)
}
}
object SPBCryptor {
final val DefaultIterationCount = 1000
final val DefaultSaltSize = 16
private final val KeyLength = 256
private def mkSecureRandom = SecureRandom.getInstanceStrong
private def mkSecretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256")
private def mkSecretKeySpec(keyBytes: Array[Byte]) = new SecretKeySpec(keyBytes, "AES")
private def mkCipher = Cipher.getInstance("AES/CTR/NoPadding")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment