大家好,我系苍王。
以下是我这个系列的相关文章,有兴趣可以参考一下,可以给个喜欢或者关注我的文章。
[[Android]如何做一个崩溃率少于千分之三噶应用app--章节列表]
技术一直都在发展,这个年代应该最热门当属区块链技术,而ETH是区块链发展不可或缺的一环。很多不了解的人都觉得区块链是后端实现的技术,前端没啥参活的事情,其实并不然。
区块链最基础也是最重要的要素——安全,那么涉及到安全,就有一个基础的技术,加密和解密。不远的未来,将会涌现的技术要求就是对加密和解密技术的原理应用的理解,犹如现金对音视频工程师一样渴求。
这节就介绍一个ETH钱包的创建,里面将会涉及一些基础加密的原理。
创建钱包
1.启动钱包加密服务
//跳转到加密服务
Intent generatingService = new Intent(this, WalletGenService.class);
//钱包密码
generatingService.putExtra("PASSWORD", data.getStringExtra("PASSWORD"));
if (data.hasExtra("PRIVATE_KEY"))
generatingService.putExtra("PRIVATE_KEY", data.getStringExtra("PRIVATE_KEY"));
//启动创建钱包服务
startService(generatingService);
final Handler handler = new Handler();
generateRefreshCount = 0;
final int walletcount = WalletStorage.getInstance(this).getFullOnly().size();
Runnable runnable = new Runnable() {
public void run() {
try {
if(walletcount < WalletStorage.getInstance(MainActivity.this).getFullOnly().size()) {
//更新钱包列表
((FragmentWallets) fragments[1]).update();
return;
}
} catch (Exception e) {
e.printStackTrace();
}
if (generateRefreshCount++ < 8)
handler.postDelayed(this, 3000)
}
};
handler.postDelayed(runnable, 4000);
WalletGenService是一个IntentService,创建完成后就会结束服务
@Override
protected void onHandleIntent(Intent intent) {
//获取密码
String password = intent.getStringExtra("PASSWORD");
String privatekey = "";
//不一定有私钥
if (intent.hasExtra("PRIVATE_KEY")) {
normalMode = false; //如果没有私钥,就是正常创建钱包,有私钥是扫码创建钱包
privatekey = intent.getStringExtra("PRIVATE_KEY");
}
//创建或添加钱包的通知
sendNotification();
try {
String walletAddress;
if (normalMode) { // 创建新的密钥
walletAddress = OwnWalletUtils.generateNewWalletFile(password, new File(this.getFilesDir(), ""), true); //获取钱包地址
} else { // Privatekey passed //通过私钥创建,秘钥对
ECKeyPair keys = ECKeyPair.create(Hex.decode(privatekey));
walletAddress = OwnWalletUtils.generateWalletFile(password, keys, new File(this.getFilesDir(), ""), true); //获取钱包地址
}
//添加到钱包存储仓库
WalletStorage.getInstance(this).add(new FullWallet("0x" + walletAddress, walletAddress), this);
//命名转换
AddressNameConverter.getInstance(this).put("0x" + walletAddress, "Wallet " + ("0x" + walletAddress).substring(0, 6), this);
Settings.walletBeingGenerated = false;
//结束时再次拼接通知
finished("0x" + walletAddress);
} catch (CipherException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchProviderException e) {
e.printStackTrace();
}
}
OwnWalletUtils用于钱包的工具类
//创建新钱包
public static String generateNewWalletFile(
String password, File destinationDirectory, boolean useFullScrypt)
throws CipherException, IOException, InvalidAlgorithmParameterException,
NoSuchAlgorithmException, NoSuchProviderException {
//创建密钥对
ECKeyPair ecKeyPair = Keys.createEcKeyPair();
return generateWalletFile(password, ecKeyPair, destinationDirectory, useFullScrypt);
}
public static String generateWalletFile(
String password, ECKeyPair ecKeyPair, File destinationDirectory, boolean useFullScrypt)
throws CipherException, IOException {
WalletFile walletFile; //钱包文件
if (useFullScrypt) { //一般使用全加密
walletFile = Wallet.createStandard(password, ecKeyPair);
} else {
walletFile = Wallet.createLight(password, ecKeyPair);
}
//获取加密文件名
String fileName = getWalletFileName(walletFile);
File destination = new File(destinationDirectory, fileName);
//将钱包文件放到指定目录
ObjectMapper objectMapper = ObjectMapperFactory.getObjectMapper();
objectMapper.writeValue(destination, walletFile);
return fileName;
}
Wallet启动标准创建
public static WalletFile createStandard(String password, ECKeyPair ecKeyPair)
throws CipherException {
return create(password, ecKeyPair, N_STANDARD, P_STANDARD);
}
//创建钱包文件 n =1<<18,p = 1
public static WalletFile create(String password, ECKeyPair ecKeyPair, int n, int p)
throws CipherException {
//32位随机数
byte[] salt = generateRandomBytes(32);
//衍生钥匙,使用了Scrypt加密(sha-256)
byte[] derivedKey = generateDerivedScryptKey(
password.getBytes(Charset.forName("UTF-8")), salt, n, R, p, DKLEN);
//加密钥,截取衍生钥的前16个字符
byte[] encryptKey = Arrays.copyOfRange(derivedKey, 0, 16);
//16位随机数
byte[] iv = generateRandomBytes(16);
//私钥字符数组
byte[] privateKeyBytes =
Numeric.toBytesPadded(ecKeyPair.getPrivateKey(), Keys.PRIVATE_KEY_SIZE);
//密码文本,使用了AES加密
byte[] cipherText = performCipherOperation(
Cipher.ENCRYPT_MODE, iv, encryptKey, privateKeyBytes);
//衍生钥和密码文本使用sha-3加密标准Keccak-256 散列算法
byte[] mac = generateMac(derivedKey, cipherText);
return createWalletFile(ecKeyPair, cipherText, iv, salt, mac, n, p);
}
衍生钥使用的是HmacSHA256加密算法,可以使用native 和java来加密,当然native会快一点。
public static byte[] scrypt(byte[] passwd, byte[] salt, int N, int r, int p, int dkLen) throws GeneralSecurityException {
//scyyptN使用Native加密,scryptJ使用Java加密
return native_library_loaded ? scryptN(passwd, salt, N, r, p, dkLen) : scryptJ(passwd, salt, N, r, p, dkLen);
}
HMAC(散列消息身份验证码: Hashed Message Authentication Code)
它不是散列函数,而是采用散列函数(sha256)与共享密钥一起使用的消息身份验证机制。
可以知道衍生钥是一同用于密码加密,用于身份验证机制。
而传输的密文,使用了AES加密,AES算法用于传递不适合明文传输的报文
private static byte[] performCipherOperation(
int mode, byte[] iv, byte[] encryptKey, byte[] text) throws CipherException {
try {
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
SecretKeySpec secretKeySpec = new SecretKeySpec(encryptKey, "AES");
cipher.init(mode, secretKeySpec, ivParameterSpec);
return cipher.doFinal(text);
……
}
创建钱包,写入相应的参数,也就是一大寸加密字符
private static WalletFile createWalletFile(
ECKeyPair ecKeyPair, byte[] cipherText, byte[] iv, byte[] salt, byte[] mac,
int n, int p) {
//新建钱包文件设定地址
WalletFile walletFile = new WalletFile();
walletFile.setAddress(Keys.getAddress(ecKeyPair));
//创建加密对象
WalletFile.Crypto crypto = new WalletFile.Crypto();
//设置加密 aes-128-ctr
crypto.setCipher(CIPHER);
//设置加密描述 ,取两位数的16进制
crypto.setCiphertext(Numeric.toHexStringNoPrefix(cipherText));
walletFile.setCrypto(crypto);
//设置加密参数
WalletFile.CipherParams cipherParams = new WalletFile.CipherParams();
cipherParams.setIv(Numeric.toHexStringNoPrefix(iv));
crypto.setCipherparams(cipherParams);
//设置kdf参数
crypto.setKdf(SCRYPT);
WalletFile.ScryptKdfParams kdfParams = new WalletFile.ScryptKdfParams();
kdfParams.setDklen(DKLEN);
kdfParams.setN(n);
kdfParams.setP(p);
kdfParams.setR(R);
kdfParams.setSalt(Numeric.toHexStringNoPrefix(salt));
crypto.setKdfparams(kdfParams);
crypto.setMac(Numeric.toHexStringNoPrefix(mac));
walletFile.setCrypto(crypto);
walletFile.setId(UUID.randomUUID().toString());
walletFile.setVersion(CURRENT_VERSION);
return walletFile;
}
重点说一下公钥私钥对创建,其中使用了椭圆加密算法
ECKeyPair ecKeyPair = Keys.createEcKeyPair();
public static ECKeyPair createEcKeyPair() throws InvalidAlgorithmParameterException,
NoSuchAlgorithmException, NoSuchProviderException {
//椭圆曲线密码创建
KeyPair keyPair = createSecp256k1KeyPair();
return ECKeyPair.create(keyPair);
}
/**
* Create a keypair using SECP-256k1 curve. 椭圆密码
*
* Private keypairs are encoded using PKCS8 公钥密码标注
*
*
Private keys are encoded using X.509 数字证书
*/
static KeyPair createSecp256k1KeyPair() throws NoSuchProviderException,
NoSuchAlgorithmException, InvalidAlgorithmParameterException {
//android security框架内置,KeyPairGenerator为抽奖类,返回实体类
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("ECDSA", "SC");
//
ECGenParameterSpec ecGenParameterSpec = new ECGenParameterSpec("secp256k1");
keyPairGenerator.initialize(ecGenParameterSpec, new SecureRandom());
return keyPairGenerator.generateKeyPair();
}
使用了EC的KeyPairGeneratorSpi来初始化参数,并计算出公钥和私钥对,这里就涉及到密码学的椭圆曲线计算了。
public KeyPair generateKeyPair()
{
if (!initialised)
{
initialize(strength, new SecureRandom());
}
//公钥私钥的加密引擎和加密参数
AsymmetricCipherKeyPair pair = engine.generateKeyPair();
ECPublicKeyParameters pub = (ECPublicKeyParameters)pair.getPublic();
ECPrivateKeyParameters priv = (ECPrivateKeyParameters)pair.getPrivate();
//先计算出公钥
if (ecParams instanceof ECParameterSpec)
{
ECParameterSpec p = (ECParameterSpec)ecParams;
BCECPublicKey pubKey = new BCECPublicKey(algorithm, pub, p, configuration);
return new KeyPair(pubKey,
new BCECPrivateKey(algorithm, priv, pubKey, p, configuration));
}
else if (ecParams == null)
{
return new KeyPair(new BCECPublicKey(algorithm, pub, configuration),
new BCECPrivateKey(algorithm, priv, configuration));
}
else
{
java.security.spec.ECParameterSpec p = (java.security.spec.ECParameterSpec)ecParams;
BCECPublicKey pubKey = new BCECPublicKey(algorithm, pub, p, configuration);
//返回公钥私钥对
return new KeyPair(pubKey, new BCECPrivateKey(algorithm, priv, pubKey, p, configuration));
}
}
椭圆曲线加密体制(Elliptic Curve Cryptography,ECC))也是一个基于加法阶数难求问题的密码方案,暂时看来如果参数选择适当,没有量子计算级别的算力是无法攻破的。
椭圆曲线算法破解是指允许使用加法来完成。
然后P+Q = R
具体原理只能之后补上了。
下一节将会介绍使用数字货币传输。
群1已满,可以进群2学习组件化