我无法使用曲线X,Y和D相同的值使用Curve P521,ECDH-ES和A256GCM在Java和Go中进行加密/解密。当我尝试从Go和Decrypt中获取加密值时在Java中失败,反之亦然,失败原因是:
开始:方形/跳跃:密码原语中的错误
Java:AES / GCM / NoPadding解密失败:GCM中的mac检查失败
这为什么不起作用?
!!!更新!!!我还添加了代码来解析JWK以在Go中创建我的KeyPair。 (我使用了Java程序,并将密钥对打印到json。)
我注意到的是,有时Java加密值可以在Go中解析,有时则不能。我认为GCM解密中的某些内容可能在Go中无法正常运行。
package main
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/x509"
"encoding/pem"
"fmt"
"log"
"math/big"
"os"
b64 "encoding/base64"
//"github.com/contiamo/jwt"
gojose "gopkg.in/square/go-jose.v2"
//jwtgo "github.com/dgrijalva/jwt-go"
)
func main() {
testgojmx()
}
func testgojmx() {
plaintext := []byte("test string")
xEnc := "AVuFsno89wJ5xT2z63iznxVO8H5gsfcHmS1XJ_JbfEzIsudqjrvKGrzxJT96-dmP_NY7KeMvyJEUInmqcqCWbzcQ"
yEnc := "ANv5hayQ3_TwMcFqPrtw-a9wNkfQuynuWhhbWOXYvGArdvibDGYRIRx3O5gAjfyumpibZFQ0K0jrjb09YP3AVbtc"
dEnc := "AGPoHUdXajyyRLV0bAokQTnDzlO7Kjs1zSucSu69CGfSwpg7oXSxlfptApD-5O47d1PX3y0ag5228XsPFXVzYnH0"
x := new(big.Int)
temp, _ := b64.URLEncoding.DecodeString(xEnc)
x = x.SetBytes(temp)
y := new(big.Int)
temp, _ = b64.URLEncoding.DecodeString(yEnc)
y = y.SetBytes(temp)
d := new(big.Int)
temp, _ = b64.URLEncoding.DecodeString(dEnc)
d = d.SetBytes(temp)
privkey := new(ecdsa.PrivateKey)
privkey.PublicKey.Curve = elliptic.P521()
privkey.D = d
privkey.PublicKey.X = x
privkey.PublicKey.Y = y
//javaKey := `{"kty":"EC","d":"AGPoHUdXajyyRLV0bAokQTnDzlO7Kjs1zSucSu69CGfSwpg7oXSxlfptApD-5O47d1PX3y0ag5228XsPFXVzYnH0","crv":"P-521","x":"AVuFsno89wJ5xT2z63iznxVO8H5gsfcHmS1XJ_JbfEzIsudqjrvKGrzxJT96-dmP_NY7KeMvyJEUInmqcqCWbzcQ","y":"ANv5hayQ3_TwMcFqPrtw-a9wNkfQuynuWhhbWOXYvGArdvibDGYRIRx3O5gAjfyumpibZFQ0K0jrjb09YP3AVbtc"}`
//jwkSet, err := jwk.ParseString(javaKey)
//if err != nil {
// panic(err)
//}
//key, err := jwkSet.Keys[0].Materialize()
//if err != nil {
// panic(err)
//}
//privkey := key.(*ecdsa.PrivateKey)
fmt.Printf("X: %d\nY: %d\nD: %d\n", privkey.X, privkey.Y, privkey.D)
encrypter, err := gojose.NewEncrypter(gojose.A256GCM, gojose.Recipient{Algorithm: gojose.ECDH_ES, Key: privkey.Public()}, nil)
if err != nil {
panic(err)
}
encrypted, err := encrypter.Encrypt(plaintext)
if err != nil {
panic(err)
}
fmt.Printf("encrypted = %v\n", encrypted.Header)
compact, err := encrypted.CompactSerialize()
if err != nil {
panic(err)
}
//compact = "eyJlcGsiOnsia3R5IjoiRUMiLCJjcnYiOiJQLTUyMSIsIngiOiJBRUFNS2ZGQ3p5NlY2WmdPdEFjSEh1c0VEM0syUC1aZmdrd2xLWmxtRFJaeGVLcTh4dUx0cXJDTzFycWx5Wkh5MXpfOEVmWXFNM0F6YlI3UGNhQVdCTURkIiwieSI6IkFMUWpEQjNLWWpLQ2twUUsxd0VUVmtvbXZ1ZDRkT05LeXhMeFJVcGpsQ0ZNSnl1bXFlUjJvc0d4N0w3UC1aU19vemJDTnhLaWU1RVQtdlNXUXczRmNLMDAifSwiZW5jIjoiQTI1NkdDTSIsImFsZyI6IkVDREgtRVMifQ..4pyFf4sd5muL9Ony.TOMCKHHWd20nPU8.NN6MFByRemeyNa50yJGVUQ"
fmt.Printf("Compact Encrypted: %v\n", compact)
msg, _ := gojose.ParseEncrypted(compact)
fmt.Printf("Message from Encrypted: %v\n", msg.Header)
decrypted, err := msg.Decrypt(privkey)
fmt.Printf("Decrtyped: %s\n", decrypted)
}
@SpringBootApplication
public class EcdhjweApplication implements CommandLineRunner {
private static Logger LOG = LoggerFactory
.getLogger(EcdhjweApplication.class);
static ECKey exposedJWK = generateECKeyJwk();
public static void main(String[] args) {
SpringApplication.run(EcdhjweApplication.class, args);
}
@Override
public void run(String... args) {
LOG.info("EXECUTING : command line runner");
try {
System.out.println("D: \n" + exposedJWK.toECPrivateKey().getS());
System.out.println("X: \n" + exposedJWK.toECPublicKey().getW().getAffineX());
System.out.println("Y: \n" + exposedJWK.toECPublicKey().getW().getAffineY());
} catch (JOSEException e) {
e.printStackTrace();
}
System.out.println("======================== Encrypting ================================");
String encryptedRequest = null;
try {
encryptedRequest = encryptJWE("test string", exposedJWK.toECPublicKey());
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Encrypted Requested::: " + encryptedRequest);
//encryptedRequest = "eyJhbGciOiJFQ0RILUVTIiwiZW5jIjoiQTI1NkdDTSIsImVwayI6eyJrdHkiOiJFQyIsImNydiI6IlAtNTIxIiwieCI6IkFOSXluNGRoZTd1UkpLWDJzTkVGaVU1dDFEYmR4ZUE5UjRReGVRdk1IXy1GZ2VLWWhNSk9uR1k0LWRzMEtVbjQtRlJfZVhuNl9HLWpqWEdGaThYVGdwVjUiLCJ5IjoiQUxYVkpaMEZmcHhaQzd6andhbEdWWjdyNTJxZlg5VmNsRnY4eWlsQ1pqY3lJbnlYT1BEVlhoWDlPYVU4R1ppeVVmOU1mQndSaTAzOUNMajdiQ0duM1lPRCJ9fQ.._ASNMu9mjl02agPG.QPV7DKPV77hiLJ8.SBGhv8JRJTl_adfFNxgO0Q";
System.out.println("======================== Decrypting Request ================================");
String decryptedDetails = null;
try {
decryptedDetails = decryptJWE(encryptedRequest, exposedJWK.toECPrivateKey());
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Decrypted Request:::" + decryptedDetails);
}
//private static String encryptJWE(JSONObject payload, ECPublicKey ecPublicKey) throws Exception {
private static String encryptJWE(String payload, ECPublicKey ecPublicKey) throws Exception {
// Build JWE header
JWEHeader header = new JWEHeader.Builder(JWEAlgorithm.ECDH_ES, EncryptionMethod.A256GCM)
.build();
// Build JWE Object
JWEObject jweObjectClient = new JWEObject(header, new Payload(payload));
// Set Public Key, Encrypt
ECDHEncrypter encrypter = new ECDHEncrypter(ecPublicKey);
encrypter.getJCAContext().setContentEncryptionProvider(BouncyCastleProviderSingleton.getInstance());
jweObjectClient.encrypt(encrypter);
return jweObjectClient.serialize();
}
private static String decryptJWE(String vcnRequestJWE, ECPrivateKey ecPrivateKey) throws Exception {
// Parse JWE & validate headers
JWEObject jweObject = EncryptedJWT.parse(vcnRequestJWE);
// Set PrivateKey and Decrypt
ECDHDecrypter decrypter = new ECDHDecrypter(ecPrivateKey);
decrypter.getJCAContext().setContentEncryptionProvider(BouncyCastleProviderSingleton.getInstance());
jweObject.decrypt(decrypter);
return jweObject.getPayload().toString();
}
public static ECKey generateECKeyJwk() {
try {
// Generate EC key pair with P-521 curve
String x = "AVuFsno89wJ5xT2z63iznxVO8H5gsfcHmS1XJ_JbfEzIsudqjrvKGrzxJT96-dmP_NY7KeMvyJEUInmqcqCWbzcQ";
String y = "ANv5hayQ3_TwMcFqPrtw-a9wNkfQuynuWhhbWOXYvGArdvibDGYRIRx3O5gAjfyumpibZFQ0K0jrjb09YP3AVbtc";
String d = "AGPoHUdXajyyRLV0bAokQTnDzlO7Kjs1zSucSu69CGfSwpg7oXSxlfptApD-5O47d1PX3y0ag5228XsPFXVzYnH0";
return new ECKey.Builder(Curve.P_521, new Base64URL(x), new Base64URL(y))
.d(new Base64URL(d))
.build();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
所示的代码演示了该语言的工作原理。注释掉的字符串是从另一种语言运行的结果