英文:
Mixing tweetnacl.js with TweetNaclFast (java) for asymmetric encryption
问题
我们的项目正在使用`nacl.box`和临时密钥进行非对称加密:
encrypt(pubKey, msg) {
if (typeof msg !== 'string') {
msg = JSON.stringify(msg)
}
let ephemKeys = nacl.box.keyPair()
let msgArr = nacl.util.decodeUTF8(msg)
let nonce = nacl.randomBytes(nacl.box.nonceLength)
p(`naclRsa.pubKey=${this.pubKey}`)
let encrypted = nacl.box(
msgArr,
nonce,
nacl.util.decodeBase64(pubKey),
ephemKeys.secretKey
)
let nonce64 = nacl.util.encodeBase64(nonce)
let pubKey64 = nacl.util.encodeBase64(ephemKeys.publicKey)
let encrypted64 = nacl.util.encodeBase64(encrypted)
return {nonce: nonce64, ephemPubKey: pubKey64, encrypted: encrypted64}
}
目前我们有 `node.js` 应用程序来解密这些消息。我们希望有可能在一些功能中使用 `jvm` 语言。在 `jvm` 上似乎没有像 `tweet-nacl` 那样丰富的已建立的工具。但似乎
* `tweetnacl-java` https://github.com/InstantWebP2P/tweetnacl-java
以及它推荐的实现
° `tweetnacl-fast` <https://github.com/InstantWebP2P/tweetnacl-java/blob/master/src/main/java/com/iwebpp/crypto/TweetNaclFast.java>
是一个流行的选择。
目前不清楚在该库中是否有类似于使用临时密钥的`非对称加密`的类比。是否支持这个?请注意,如果在 `tweetnacl-java` 中不支持,我也可以考虑使用 `java` 或 `kotlin`。
英文:
Our project is using asymmetric encryption with nacl.box
and ephemeral keys:
encrypt(pubKey, msg) {
if (typeof msg !== 'string') {
msg = JSON.stringify(msg)
}
let ephemKeys = nacl.box.keyPair()
let msgArr = nacl.util.decodeUTF8(msg)
let nonce = nacl.randomBytes(nacl.box.nonceLength)
p(`naclRsa.pubKey=${this.pubKey}`)
let encrypted = nacl.box(
msgArr,
nonce,
nacl.util.decodeBase64(pubKey),
ephemKeys.secretKey
)
let nonce64 = nacl.util.encodeBase64(nonce)
let pubKey64 = nacl.util.encodeBase64(ephemKeys.publicKey)
let encrypted64 = nacl.util.encodeBase64(encrypted)
return {nonce: nonce64, ephemPubKey: pubKey64, encrypted: encrypted64}
}
We presently have node.js
apps that then decrypt these messages. We would like the option to use jvm
languages for some features. There does not seem to be the richness of established players for tweet-nacl
on the jvm
but it seems
tweetnacl-java
https://github.com/InstantWebP2P/tweetnacl-java
and its recommended implementation
° tweetnacl-fast
<https://github.com/InstantWebP2P/tweetnacl-java/blob/master/src/main/java/com/iwebpp/crypto/TweetNaclFast.java>
were a popular one.
It is unclear what the analog to the asymmetric
encryption with ephemeral keys were in that library. Is it supported? Note that I would be open to either java
or kotlin
if this were not supported in tweetnacl-java
.
答案1
得分: 1
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import com.iwebpp.crypto.TweetNaclFast;
import com.iwebpp.crypto.TweetNaclFast.Box;
import com.iwebpp.crypto.TweetNaclFast.Box.KeyPair;
...
private static EncryptedData encrypt(byte[] pubKey, String msg) {
KeyPair ephemKeys = Box.keyPair();
byte[] msgArr = msg.getBytes(StandardCharsets.UTF_8);
byte[] nonce = TweetNaclFast.randombytes(Box.nonceLength);
Box box = new Box(pubKey, ephemKeys.getSecretKey());
byte[] encrypted = box.box(msgArr, nonce);
String nonce64 = Base64.getEncoder().encodeToString(nonce);
String ephemPubKey64 = Base64.getEncoder().encodeToString(ephemKeys.getPublicKey());
String encrypted64 = Base64.getEncoder().encodeToString(encrypted);
return new EncryptedData(nonce64, ephemPubKey64, encrypted64);
}
...
class EncryptedData {
public EncryptedData(String nonce, String ephemPubKey, String encrypted) {
this.nonce = nonce;
this.ephemPubKey = ephemPubKey;
this.encrypted = encrypted;
}
public String nonce;
public String ephemPubKey;
public String encrypted;
}
let keysJS = nacl.box.keyPair();
let secretKeyJS = keysJS.secretKey;
let publicKeyJS = keysJS.publicKey;
console.log("Secret key: " + nacl.util.encodeBase64(secretKeyJS));
console.log("Public key: " + nacl.util.encodeBase64(publicKeyJS));
let nonce = "FcdzXfYwSbI0nq2WXsLe9aAh94vXSoWd";
let ephemPubKey = "Mde+9metwF1jIEij5rlZDHjAStR/pd4BN9p5JbZleSg=";
let encrypted = "hHo7caCxTU+hghcFZFv+djAkSlWKnC12xj82V2R/Iz9GdOMoTzjoCDcz9m/KbRN6i5dkYi3+Gf0YTtKlZQWFooo=";
let secretKeyJS = nacl.util.decodeBase64("YTxAFmYGm4yV2OP94E4pcD6LSsN4gcSBBAlU105l7hw=");
let decryptedFromJS = decrypt(secretKeyJS, {nonce: nonce, ephemPubKey: ephemPubKey, encrypted: encrypted});
console.log(nacl.util.encodeUTF8(decryptedFromJS)); // I've got a feeling we're not in Kansas anymore...
function decrypt(secretKey, ciphertext){
let decrypted = nacl.box.open(
nacl.util.decodeBase64(ciphertext.encrypted),
nacl.util.decodeBase64(ciphertext.nonce),
nacl.util.decodeBase64(ciphertext.ephemPubKey),
secretKey
);
return decrypted;
}
<details>
<summary>英文:</summary>
[*tweetnacl-java*][1] is a port of [*tweetnacl-js*][2]. It is therefore to be expected that both provide the same functionality. At least for the posted method this is the case, which can be implemented on the Java side with *TweetNaclFast* as follows:
<!-- language: Java-->
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import com.iwebpp.crypto.TweetNaclFast;
import com.iwebpp.crypto.TweetNaclFast.Box;
import com.iwebpp.crypto.TweetNaclFast.Box.KeyPair;
...
private static EncryptedData encrypt(byte[] pubKey, String msg) {
KeyPair ephemKeys = Box.keyPair();
byte[] msgArr = msg.getBytes(StandardCharsets.UTF_8);
byte[] nonce = TweetNaclFast.randombytes(Box.nonceLength);
Box box = new Box(pubKey, ephemKeys.getSecretKey());
byte[] encrypted = box.box(msgArr, nonce);
String nonce64 = Base64.getEncoder().encodeToString(nonce);
String ephemPubKey64 = Base64.getEncoder().encodeToString(ephemKeys.getPublicKey());
String encrypted64 = Base64.getEncoder().encodeToString(encrypted);
return new EncryptedData(nonce64, ephemPubKey64, encrypted64);
}
...
class EncryptedData {
public EncryptedData(String nonce, String ephemPubKey, String encrypted) {
this.nonce = nonce;
this.ephemPubKey = ephemPubKey;
this.encrypted = encrypted;
}
public String nonce;
public String ephemPubKey;
public String encrypted;
}
<!-- language: Java-->
-----------------
In order to demonstrate that both sides are compatible, in the following a plaintext is encrypted on the Java side and decrypted on the JavaScript side:
- First, a key pair is needed on the JavaScript side, whose public key (`publicKeyJS`) is passed to the Java side. The key pair on the JavaScript side can be generated as follows:
<!-- language: JavaScript -->
let keysJS = nacl.box.keyPair();
let secretKeyJS = keysJS.secretKey;
let publicKeyJS = keysJS.publicKey;
console.log("Secret key: " + nacl.util.encodeBase64(secretKeyJS));
console.log("Public key: " + nacl.util.encodeBase64(publicKeyJS));
<!-- language: JavaScript -->
with the following sample output:
<!-- language: none -->
Secret key: YTxAFmYGm4yV2OP94E4pcD6LSsN4gcSBBAlU105l7hw=
Public key: BDXNKDHeq0vILm8oawAGAQtdIsgwethzBTBqmsWI+R8=
<!-- language: none -->
- The encryption on the Java side is then using the `encrypt` method posted above (and `publicKeyJS`):
<!-- language: Java -->
byte[] publicKeyJS = Base64.getDecoder().decode("BDXNKDHeq0vILm8oawAGAQtdIsgwethzBTBqmsWI+R8=");
EncryptedData encryptedFromJava = encrypt(publicKeyJS, "I've got a feeling we're not in Kansas anymore...");
System.out.println("Nonce: " + encryptedFromJava.nonce);
System.out.println("Ephemeral public key: " + encryptedFromJava.ephemPubKey);
System.out.println("Ciphertext: " + encryptedFromJava.encrypted);
<!-- language: Java -->
with the following sample output:
<!-- language: none -->
Nonce: FcdzXfYwSbI0nq2WXsLe9aAh94vXSoWd
Ephemeral public key: Mde+9metwF1jIEij5rlZDHjAStR/pd4BN9p5JbZleSg=
Ciphertext: hHo7caCxTU+hghcFZFv+djAkSlWKnC12xj82V2R/Iz9GdOMoTzjoCDcz9m/KbRN6i5dkYi3+Gf0YTtKlZQWFooo=
<!-- language: none -->
- The decryption on the JS side gives the original plaintext (using `secretKeyJS`):
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
let nonce = "FcdzXfYwSbI0nq2WXsLe9aAh94vXSoWd";
let ephemPubKey = "Mde+9metwF1jIEij5rlZDHjAStR/pd4BN9p5JbZleSg=";
let encrypted = "hHo7caCxTU+hghcFZFv+djAkSlWKnC12xj82V2R/Iz9GdOMoTzjoCDcz9m/KbRN6i5dkYi3+Gf0YTtKlZQWFooo=";
let secretKeyJS = nacl.util.decodeBase64("YTxAFmYGm4yV2OP94E4pcD6LSsN4gcSBBAlU105l7hw=");
let decryptedFromJS = decrypt(secretKeyJS, {nonce: nonce, ephemPubKey: ephemPubKey, encrypted: encrypted});
console.log(nacl.util.encodeUTF8(decryptedFromJS)); // I've got a feeling we're not in Kansas anymore...
function decrypt(secretKey, ciphertext){
let decrypted = nacl.box.open(
nacl.util.decodeBase64(ciphertext.encrypted),
nacl.util.decodeBase64(ciphertext.nonce),
nacl.util.decodeBase64(ciphertext.ephemPubKey),
secretKey
);
return decrypted;
}
<!-- language: lang-html -->
<script src="https://cdn.jsdelivr.net/npm/tweetnacl-util@0.15.1/nacl-util.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/tweetnacl@1.0.3/nacl.min.js"></script>
<!-- end snippet -->
[1]: https://github.com/InstantWebP2P/tweetnacl-java
[2]: https://github.com/dchest/tweetnacl-js
</details>
# 答案2
**得分**: 0
以下是您要翻译的内容:
完整的 tweetnacl-java 代码(向 @topaco 致敬)
> 我生成了两对随机密钥,并将它们的秘密密钥保存在 application.properties 文件中,这样,我将始终拥有相同的公钥、秘密密钥和 nonce。
> KeyPair baseKeyPair = Box.keyPair();
***String baseKeyPairSecretKey = Base64.getEncoder().encodeToString(baseKeyPair.getSecretKey());***
> KeyPair ephemeralKeyPair = Box.keyPair();
***String ephemeralKeyPairSecretKey = Base64.getEncoder().encodeToString(ephemeralKeyPair.getSecretKey());***
> byte[] nonce = TweetNaclFast.randombytes(Box.nonceLength);
***String nonce64 = Base64.getEncoder().encodeToString(nonce);***
```java
private final AppConfig config; // 可以自动装配配置类
private TweetNaclFast.Box.KeyPair getBaseKeyPair() {
byte[] secretKey = Base64.getDecoder().decode(config.getTweetNACLConfig().getBaseSecretKey());
return TweetNaclFast.Box.keyPair_fromSecretKey(mySecretKey);
}
private TweetNaclFast.Box.KeyPair getEphemeralKeyPair() {
byte[] secretKey = Base64.getDecoder().decode(config.getTweetNACLConfig().getEphemeralSecretKey());
return TweetNaclFast.Box.keyPair_fromSecretKey(mySecretKey);
}
private byte[] getNonce() {
return Base64.getDecoder().decode(config.getTweetNACLConfig().getNonce().getBytes(StandardCharsets.UTF_8));
}
public String encrypt(String msg) {
TweetNaclFast.Box.KeyPair baseKeyPair = getBaseKeyPair();
TweetNaclFast.Box.KeyPair ephemeralKeyPair = getEphemeralKeyPair();
byte[] msgArr = msg.getBytes(StandardCharsets.UTF_8);
byte[] nonce = getNonce();
TweetNaclFast.Box box = new TweetNaclFast.Box(baseKeyPair.getPublicKey(), ephemeralKeyPair.getSecretKey());
byte[] encryptedData = box.box(msgArr, nonce);
return Base64.getEncoder().encodeToString(encryptData);
}
public String decrypt(String encryptedData) {
TweetNaclFast.Box.KeyPair baseKeyPair = getBaseKeyPair();
TweetNaclFast.Box.KeyPair ephemeralKeyPair = getEphemeralKeyPair();
byte[] nonce = getNonce();
TweetNaclFast.Box box = new TweetNaclFast.Box(ephemeralKeyPair.getPublicKey(), baseKeyPair.getSecretKey());
byte[] boxToOpen = Base64.getDecoder().decode(encryptedData);
byte[] decryptedData = box.open(boxToOpen, nonce);
return new String(decryptedData, StandardCharsets.UTF_8);
}
> 请注意这两行
> TweetNaclFast.Box box = new TweetNaclFast.Box(baseKeyPair.getPublicKey(), ephemeralKeyPair.getSecretKey());
> TweetNaclFast.Box box = new TweetNaclFast.Box(ephemeralKeyPair.getPublicKey(), baseKeyPair.getSecretKey());
return encryptAndDecryptData.encrypt("Friday"); // JHo/tk/Jpp2rpxpzIIgBhVhK/CBZLg==
return encryptAndDecryptData.decrypt("JHo/tk/Jpp2rpxpzIIgBhVhK/CBZLg==") //Friday
英文:
My complete code for tweetnacl-java (Kudos to @topaco)
> I generated two random key-pairs and saved their secret keys in the application.properties file, so that, i will always have the same pub&sec along with the nonce.
> KeyPair baseKeyPair= Box.keyPair();
String baseKeyPairSecretKey = Base64.getEncoder().encodeToString(baseKeyPair.getSecretKey());
> KeyPair ephemeralKeyPair= Box.keyPair();
String ephemeralKeyPairSecretKey = Base64.getEncoder().encodeToString(ephemeralKeyPair.getSecretKey());
> byte[] nonce = TweetNaclFast.randombytes(Box.nonceLength);
String nonce64 = Base64.getEncoder().encodeToString(nonce);
private final AppConfig config; //you can autowire the config class
private TweetNaclFast.Box.KeyPair getBaseKeyPair() {
byte[] secretKey = Base64.getDecoder().decode(config.getTweetNACLConfig().getBaseSecretKey());
return TweetNaclFast.Box.keyPair_fromSecretKey(mySecretKey);
}
private TweetNaclFast.Box.KeyPair getEphemeralKeyPair() {
byte[] secretKey = Base64.getDecoder().decode(config.getTweetNACLConfig().getEphemeralSecretKey());
return TweetNaclFast.Box.keyPair_fromSecretKey(mySecretKey);
}
private byte[] getNonce() {
return Base64.getDecoder().decode(config.getTweetNACLConfig().getNonce().getBytes(StandardCharsets.UTF_8));
}
public String encrypt(String msg) {
TweetNaclFast.Box.KeyPair baseKeyPair = getBaseKeyPair();
TweetNaclFast.Box.KeyPair ephemeralKeyPair = getEphemeralKeyPair();
byte[] msgArr = msg.getBytes(StandardCharsets.UTF_8);
byte[] nonce = getNonce();
TweetNaclFast.Box box = new TweetNaclFast.Box(baseKeyPair.getPublicKey(), ephemeralKeyPair.getSecretKey());
byte[] encryptedData = box.box(msgArr, nonce);
return Base64.getEncoder().encodeToString(encryptData);
}
public String decrypt(String encryptedData) {
TweetNaclFast.Box.KeyPair baseKeyPair = getBaseKeyPair();
TweetNaclFast.Box.KeyPair ephemeralKeyPair = getEphemeralKeyPair();
byte[] nonce = getNonce();
TweetNaclFast.Box box = new TweetNaclFast.Box(ephemeralKeyPair.getPublicKey(), baseKeyPair.getSecretKey());
byte[] boxToOpen = Base64.getDecoder().decode(encryptedData);
byte[] decryptedData = box.open(boxToOpen, nonce);
return new String(decryptedData, StandardCharsets.UTF_8);
}
> Please, note these two lines
> TweetNaclFast.Box box = new TweetNaclFast.Box(baseKeyPair.getPublicKey(), ephemeralKeyPair.getSecretKey());
> TweetNaclFast.Box box = new TweetNaclFast.Box(ephemeralKeyPair.getPublicKey(), baseKeyPair.getSecretKey());
return encryptAndDecryptData.encrypt("Friday"); // JHo/tk/Jpp2rpxpzIIgBhVhK/CBZLg==
return encryptAndDecryptData.decrypt("JHo/tk/Jpp2rpxpzIIgBhVhK/CBZLg==") //Friday
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论