添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

Java crypto is like an architect building a house. Architect only knows how to design a house, but needs a construction company to actually build it. In Java, only crypto interface is defined, and a provider is required to actually implement the methods. There are different providers , but one has stood out in the test of times.

BouncyCastle

De facto open source standard for the crypto implementation is BouncyCastle (BC). It is maintained for both Java and C# and trusted by sources like Android and OkHttp .

BouncyCastle and Android

Due to Android including a cut down version of BC in the SDK, the Australian crypto provider could not at all be used as a provider in earlier phone systems. The package names are the same and would clash. To fix this problem, since Android 3, the phone’s internal copy was renamed to “com.android.org.bouncycastle”.

However, if using "BC" as the crypto provider:

Mac.getInstance("HmacSHA256", "BC")
$ openssl ecparam -genkey -out testsk.pem -name prime256v1
$ openssl ec -in testsk.pem -pubout -text
Private-Key: (256 bit)
priv:
    6c:ab:c1:a8:59:64:9d:b7:58:e9:25:bc:35:53:f1:
    4f:4e:30:65:de:b3:c6:cf:7e:f8:31:cb:14:a6:93:
    55:a3
    04:6c:e1:2c:7a:bd:ff:05:31:98:ed:e8:8a:bc:d3:
    c3:1c:ee:00:ae:59:8b:a4:6a:1b:f9:61:c9:09:fe:
    b3:b0:1e:53:1f:af:56:6b:af:9b:4b:db:14:73:4b:
    f0:ad:c3:56:18:13:bf:9f:2f:40:fc:26:ab:2b:fe:
    cf:d6:4f:02:42
// the first 04 is the header byte
val rawPublicKey = Bytes("046ce12c7abdff053198ede88abcd3c31cee00ae598ba46a1bf961c909feb3b01e531faf566baf9b4bdb14734bf0adc3561813bf9f2f40fc26ab2bfecfd64f0242")
val params = ECNamedCurveTable.getParameterSpec("secp256r1")
val keySpec =
    ECPublicKeySpec(params.curve.decodePoint(rawPublicKey.byteArray), params)
val keyFactory = KeyFactory.getInstance("EC", BouncyCastleProvider())
val javaPublicKey = keyFactory.generatePublic(keySpec) as ECPublicKey
val convertedBack = Bytes(65)
convertedBack.set(0, 0x04)
// the BigInteger can sometimes be 31 bytes. Then 0x00 needs to be prepended 
convertedBack.set(1, publicPoint.affineX.toBytes(32))
convertedBack.set(32, publicPoint.affineY.toBytes(32))
require(rawPublicKey == convertedBack)
val rawPrivateKey = Bytes("6cabc1a859649db758e925bc3553f14f4e3065deb3c6cf7ef831cb14a69355a3").byteArray
val d = BigInteger(1, rawPrivateKey)
val curveSpec = ECParameterSpec(params.curve, params.g, params.n, params.h)
val privateKeySpec = ECPrivateKeySpec(d, curveSpec)
val keyFactory = KeyFactory.getInstance("EC")
val privateKey = keyFactory.generatePrivate(privateKeySpec) as ECPrivateKey
// assure the d value is always 32 bytes long
val convertedBack = privateKey.d.toBytes(32)
require(rawPrivateKey == convertedBack)
val message = Bytes("aabb")
val signer = Signature.getInstance("SHA256withPLAIN-ECDSA", BouncyCastleProvider())
signer.initSign(privateKey)
signer.update(message.byteArray)
val signature = signer.sign()
val verifier = Signature.getInstance("SHA256withPLAIN-ECDSA", BouncyCastleProvider())
verifier.initVerify(publicKey)
verifier.update(message.byteArray)
val result = verifier.verify(signature)
require(result == true)
val message = byteArrayOf(0, 1, 2)
val key: SecretKey = SecretKeySpec(sharedSecretKey, "HmacSHA256")
val mac: Mac = Mac.getInstance("HmacSHA256", BouncyCastleProvider())
mac.init(key)
val hmac = mac.doFinal(message)

There is the more modern Tink, which promises a cleaner and harder to misuse API. It is from Google developers and supported on multiple platforms, including Java and Android. This is a welcome change to Java’s crypto space, where currently the HMAC instance has to be initialised with a String value:

SecretKeySpec(sharedSecretKey, "HmacSHA256")

Since Java doesn’t provide the implementation for the crypto functions, a separate provider needs to be used. BouncyCastle is suitable for this task. Unfortunately, in Android, it is already included in the SDK. Namespace conflicts arise and the real BC provider can be used by inputting BouncyCastleProvider() instead of "BC".

Sample code: github

hmkit-crypto-telematics: github