Skip to content

Instantly share code, notes, and snippets.

@tentenponce
Last active November 26, 2019 08:01
Show Gist options
  • Save tentenponce/9ec93a5b5e3e2d5ec52e8915998d8352 to your computer and use it in GitHub Desktop.
Save tentenponce/9ec93a5b5e3e2d5ec52e8915998d8352 to your computer and use it in GitHub Desktop.
import org.apache.commons.codec.binary.Base64
import org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util
import org.bouncycastle.jce.ECNamedCurveTable
import org.bouncycastle.jce.spec.ECNamedCurveSpec
import org.spongycastle.jce.provider.BouncyCastleProvider
import org.web3j.crypto.ECKeyPair
import org.web3j.utils.Numeric
import java.math.BigInteger
import java.security.KeyFactory
import java.security.Security
import java.security.interfaces.ECPrivateKey
import java.security.interfaces.ECPublicKey
import java.security.spec.ECPoint
import javax.crypto.Cipher
object ECCUtil {
private const val ECC_ALGORITHM = "ECIES"
private const val KEY_FACTORY_ALGORITHM = "ECDSA"
private const val CURVE_NAME = "secp256k1"
private const val HEXADECIMAL = 16
fun encryptEcc(input: String, publicKey: String): String {
Security.insertProviderAt(BouncyCastleProvider(), 1)
val cipher = Cipher.getInstance(ECC_ALGORITHM, BouncyCastleProvider.PROVIDER_NAME)
cipher.init(Cipher.ENCRYPT_MODE, toEcPublicKey(publicKey))
val encryptedText = cipher.doFinal(input.toByteArray())
return Base64.encodeBase64String(encryptedText)
}
fun decryptEcc(input: String, privateKey: String): String {
Security.insertProviderAt(BouncyCastleProvider(), 1)
val cipher = Cipher.getInstance(ECC_ALGORITHM, BouncyCastleProvider.PROVIDER_NAME)
cipher.init(Cipher.DECRYPT_MODE, toEcPrivateKey(privateKey))
val decodedInput = Base64.decodeBase64(input)
val decryptedText = cipher.doFinal(decodedInput)
return String(decryptedText)
}
private fun toEcPublicKey(publicKey: String): ECPublicKey {
val params = ECNamedCurveTable.getParameterSpec(CURVE_NAME)
val curveSpec = ECNamedCurveSpec(CURVE_NAME, params.curve, params.g, params.n)
val pubKeyX = publicKey.substring(0, publicKey.length / 2)
val pubKeyY = publicKey.substring(publicKey.length / 2)
val ecPoint = ECPoint(BigInteger(pubKeyX, HEXADECIMAL), BigInteger(pubKeyY, HEXADECIMAL))
val params2 = EC5Util.convertSpec(curveSpec.curve, params)
val keySpec = java.security.spec.ECPublicKeySpec(ecPoint, params2)
val factory = KeyFactory.getInstance(KEY_FACTORY_ALGORITHM)
return factory.generatePublic(keySpec) as ECPublicKey
}
private fun toEcPrivateKey(privateKey: String): ECPrivateKey {
val ecKeyPair = ECKeyPair.create(Numeric.hexStringToByteArray(privateKey))
val params = ECNamedCurveTable.getParameterSpec(CURVE_NAME)
val curveSpec = ECNamedCurveSpec(CURVE_NAME, params.curve, params.g, params.n)
val keySpec = java.security.spec.ECPrivateKeySpec(
ecKeyPair.privateKey,
curveSpec
)
val factory = KeyFactory.getInstance(KEY_FACTORY_ALGORITHM)
return factory.generatePrivate(keySpec) as ECPrivateKey
}
}
@Ignore("for stress test purposes only")
@Test
fun `should encrypt and decrypt successfully`() {
repeat(100) {
val walletFactory = WalletFactory()
val mnemonic = walletFactory.generateMnemonic()
val password = walletFactory.generatePassphrase()
val wallet = walletFactory.generateWallet(mnemonic, password)
val encrypted = ECCUtil.encryptEcc(TEXT_TO_ENCRYPT, wallet.publicKey)
val decrypted = ECCUtil.decryptEcc(encrypted, wallet.privateKey)
assert(decrypted == TEXT_TO_ENCRYPT)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment