android curve25519

import org.libsodium.jni.NaCl
import org.libsodium.jni.SodiumException
import org.libsodium.jni.crypto SecretBox
import org.libsodium.jni.keys.KeyPair
import java.util.*

fun generateCurve25519KeyPair(): Pair<ByteArray, ByteArray> {
    // 初始化 libsodium 库
    NaCl.init()

    // 创建一个新的KeyPair实例
    val keyPair = KeyPair()

    // 生成Curve25519密钥对
    try {
        keyPair.generateKeyPair()
    } catch (e: SodiumException) {
        throw RuntimeException("Failed to generate Curve25519 key pair.", e)
    }

    // 提取公钥和私钥
    val publicKey = keyPair.publicKey
    val privateKey = keyPair.secretKey

    // 返回密钥对
    return Pair(publicKey.copyOf(), privateKey.copyOf())
}

// 使用函数生成密钥对
val (publicKey, privateKey) = generateCurve25519KeyPair()

// 打印密钥(实际操作中应妥善保存,不要直接打印)
println("Public Key: ${publicKey.toHexString()}")
println("Private Key: ${privateKey.toHexString()}")

// 辅助函数,将字节数组转为十六进制字符串
fun ByteArray.toHexString() = joinToString(separator = "") { "%02x".format(it) }
 

 

 

 

 

import android.util.Base64;

import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyAgreement;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.ShortBufferException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class ECDH {
    static {
        Security.insertProviderAt(new org.spongycastle.jce.provider.BouncyCastleProvider(), 1);
    }

    public static KeyPair generateECDH() {
        try {
            ECGenParameterSpec ecParamSpec = new ECGenParameterSpec("secp256k1");
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("ECDH", "SC");
            keyPairGenerator.initialize(ecParamSpec);

            KeyPair keyPair = keyPairGenerator.generateKeyPair();

            return keyPair;
        } catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException
                | NoSuchProviderException e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String getPublicKey(KeyPair keyPair) {
        return Base64.encodeToString(keyPair.getPublic().getEncoded(), Base64.DEFAULT).replaceAll("\n", "");
    }

    public static PublicKey stringToPublicKey(String key) throws UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException {
        byte[] keyBytes = Base64.decode(key.getBytes("utf-8"), Base64.DEFAULT);
        X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("ECDH", "SC");
        PublicKey publicKey = keyFactory.generatePublic(spec);
        return publicKey;
    }

    public static SecretKey computeECDHSecret(PrivateKey privateKey, String publicKey) {
        try {
            KeyAgreement keyAgreement = KeyAgreement.getInstance("ECDH", "SC");
            keyAgreement.init(privateKey);

            keyAgreement.doPhase(stringToPublicKey(publicKey), true);
            SecretKey key = keyAgreement.generateSecret("AES");
            return key;
        } catch (InvalidKeyException | NoSuchAlgorithmException
                | NoSuchProviderException | UnsupportedEncodingException
                | InvalidKeySpecException e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String encryptAuthIV(SecretKey key, String plainText) {
        try {
            byte[] iv = new SecureRandom().generateSeed(16);

            IvParameterSpec ivSpec = new IvParameterSpec(iv);
            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "SC");
            byte[] plainTextBytes = plainText.getBytes("UTF-8");
            byte[] cipherText;

            cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
            cipherText = new byte[cipher.getOutputSize(plainTextBytes.length)];


            int encryptLength = cipher.update(plainTextBytes, 0,
                    plainTextBytes.length, cipherText, 0);
            encryptLength += cipher.doFinal(cipherText, encryptLength);

            byte[] concatenatedBytes = new byte[iv.length + cipherText.length];
            System.arraycopy(iv, 0, concatenatedBytes, 0, iv.length);
            System.arraycopy(cipherText, 0, concatenatedBytes, iv.length, cipherText.length);

            return Base64.encodeToString(concatenatedBytes, Base64.DEFAULT).replaceAll("\n", "");
        } catch (NoSuchAlgorithmException | NoSuchProviderException
                | NoSuchPaddingException | InvalidKeyException
                | InvalidAlgorithmParameterException
                | UnsupportedEncodingException | ShortBufferException
                | IllegalBlockSizeException | BadPaddingException e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String decryptAuthIV(SecretKey key, String cipherText) {
        try {
            Key decryptionKey = new SecretKeySpec(key.getEncoded(), key.getAlgorithm());

            byte[] iv = new byte[16];
            byte[] cipherBytes = Base64.decode(cipherText.getBytes("utf-8"), Base64.DEFAULT);
            System.arraycopy(cipherBytes, 0, iv, 0, iv.length);

            IvParameterSpec ivSpec = new IvParameterSpec(iv);
            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "SC");

            byte[] plainText;
            byte[] cipherTextBytes = new byte[cipherBytes.length - iv.length];

            System.arraycopy(cipherBytes, iv.length, cipherTextBytes, 0, cipherBytes.length - iv.length);

            cipher.init(Cipher.DECRYPT_MODE, decryptionKey, ivSpec);
            plainText = new byte[cipher.getOutputSize(cipherTextBytes.length)];
            int decryptLength = cipher.update(cipherTextBytes, 0,
                    cipherTextBytes.length, plainText, 0);
            decryptLength += cipher.doFinal(plainText, decryptLength);

            return new String(plainText, "UTF-8");
        } catch (NoSuchAlgorithmException | NoSuchProviderException
                | NoSuchPaddingException | InvalidKeyException
                | InvalidAlgorithmParameterException
                | IllegalBlockSizeException | BadPaddingException
                | ShortBufferException | UnsupportedEncodingException e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String bytesToHex(byte[] data, int length) {
        String digits = "0123456789ABCDEF";
        StringBuffer buffer = new StringBuffer();

        for (int i = 0; i != length; i++) {
            int v = data[i] & 0xff;

            buffer.append(digits.charAt(v >> 4));
            buffer.append(digits.charAt(v & 0xf));
        }

        return buffer.toString();
    }

    public static String bytesToHex(byte[] data) {
        return bytesToHex(data, data.length);
    }

    public static byte[] hexToBytes(String string) {
        int length = string.length();
        byte[] data = new byte[length / 2];
        for (int i = 0; i < length; i += 2) {
            data[i / 2] = (byte) ((Character.digit(string.charAt(i), 16) << 4) + Character
                    .digit(string.charAt(i + 1), 16));
        }
        return data;
    }
}

 

 

 

 

import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import com.example.ecdhsample.ui.theme.ECDHSampleTheme
import com.google.crypto.tink.aead.AeadConfig
import com.google.crypto.tink.subtle.AesGcmJce
import java.security.KeyPair
import java.security.KeyPairGenerator
import java.security.PrivateKey
import java.security.PublicKey
import javax.crypto.KeyAgreement


class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            ECDHSampleTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    Greeting("Android")
                }
            }
        }

        val aliceKpg: KeyPairGenerator = KeyPairGenerator.getInstance("EC")
        aliceKpg.initialize(256) // Key size in bits

        val aliceKeyPair: KeyPair = aliceKpg.generateKeyPair()

        // Generate key pair for Bob
        val bobKpg: KeyPairGenerator = KeyPairGenerator.getInstance("EC")
        bobKpg.initialize(256) // Key size in bits

        val bobKeyPair: KeyPair = bobKpg.generateKeyPair()

        // Alice's private key and Bob's public key
        val alicePrivateKey: PrivateKey = aliceKeyPair.private
        val bobPublicKey: PublicKey = bobKeyPair.public

        // Alice performs the key agreement

        // Alice performs the key agreement
        val aliceKeyAgreement: KeyAgreement = KeyAgreement.getInstance("ECDH")
        aliceKeyAgreement.init(alicePrivateKey)
        aliceKeyAgreement.doPhase(bobPublicKey, true)

        // Generate shared secret
        val sharedSecretAlice: ByteArray = aliceKeyAgreement.generateSecret()

        // Bob performs the key agreement
        val bobPrivateKey: PrivateKey = bobKeyPair.private
        val alicePublicKey: PublicKey = aliceKeyPair.public

        val bobKeyAgreement: KeyAgreement = KeyAgreement.getInstance("ECDH")
        bobKeyAgreement.init(bobPrivateKey)
        bobKeyAgreement.doPhase(alicePublicKey, true)

        // Generate shared secret
        val sharedSecretBob: ByteArray = bobKeyAgreement.generateSecret()

        // Compare the shared secrets
        Log.d("Alice's shared secret: ", byteArrayToHexString(sharedSecretAlice)!!)
        Log.d("Bob's shared secret: ", byteArrayToHexString(sharedSecretBob)!!)

        AeadConfig.register()

        // 1. Divide by two the shared secret to have a 128 bit key
        val keyset128 = sharedSecretBob.take(16)
        val aead = AesGcmJce(keyset128.toTypedArray().toByteArray())

        // 3. Use the primitive to encrypt a plaintext
        val plainText = "This is a random message"

        val ciphertext = aead.encrypt(plainText.toByteArray(), null)
        Log.d("encrypted message = ", String(ciphertext))

        // ... or to decrypt a ciphertext.
        val decrypted = aead.decrypt(ciphertext, null)
        Log.d("decrypted message = ", String(decrypted))

    }

    private fun byteArrayToHexString(array: ByteArray): String? {
        val sb = StringBuilder()
        for (b in array) {
            sb.append(String.format("%02X", b))
        }
        return sb.toString()
    }
}

@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
    Text(
        text = "Hello $name!",
        modifier = modifier
    )
}

@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
    ECDHSampleTheme {
        

 

1. **依赖项添加**:

   在你的Android项目的`build.gradle(Module: app)`文件中添加Tink库依赖:

 

   ```groovy

   dependencies {

       implementation 'com.google.crypto.tink:tink-android:1.6.1'

   }

 

 

 

   ```kotlin

   import com.google.crypto.tink.subtle.EcdhKem

   import com.google.crypto.tink.subtle.EllipticCurves

   import java.security.KeyPairGenerator

   import java.security.spec.ECGenParameterSpec

   import javax.crypto.SecretKey

 

   // 生成客户端ECDH密钥对

   val generator: KeyPairGenerator = KeyPairGenerator.getInstance("EC")

   val ecSpec: ECGenParameterSpec = ECGenParameterSpec("secp256r1") // 或者其他曲线名称

   generator.initialize(ecSpec)

   val keyPair = generator.generateKeyPair()

   val clientPrivateKey = keyPair.private as java.security.interfaces.ECPrivateKey

 

   // 假设后端公钥已经以某种方式获取并且解析成了ECPublicKey类型

   val backendPublicKey: java.security.interfaces.ECPublicKey = ... // 解析过程

 

   // 使用Tink计算共享密钥

   val tinkPublicKey = EllipticCurves.convertToPublicKey(backendPublicKey)

   val kem = EcdhKem.newInstance(clientPrivateKey.parameters)

   val sharedSecretBytes: ByteArray = kem.deriveKey(tinkPublicKey)

 

   // sharedSecretBytes现在包含的是双方共享的密钥,可以进一步处理成AES密钥等

   val sharedSecretKey = SecretKeySpec(sharedSecretBytes, "AES") // 

 

 

 

 

  • 7
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值