如何将RSA签名添加到HTTP请求



我正在编写一个nodejs服务器来托管RESTful服务和使用这些服务的Android应用程序。

安卓应用程序应该使用RSA对其请求进行签名。

我已经完成了创建密钥对和对消息进行签名的所有相关工作。

我的问题是我不知道如何将签名发送到服务器。起初,我想简单地向请求主体添加一个签名属性,但很快意识到这是行不通的,因为这会修改原始消息,阻止服务器验证签名。

那么,如何在Android上向http请求添加RSA签名呢?

作为参考,这里是我的Android代码:

public final class MyCrypto {
public static PublicKey generateRSAKeypair(Context context, String alias) throws NoSuchProviderException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, IOException, KeyStoreException, CertificateException, UnrecoverableEntryException {
// check if keypair already exists
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
KeyStore.Entry entry = keyStore.getEntry(alias, null);
if (entry != null) {
return ((KeyStore.PrivateKeyEntry) entry).getCertificate().getPublicKey();
}
Calendar start = Calendar.getInstance();
Calendar end = Calendar.getInstance();
end.add(Calendar.YEAR, 1);
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore");
keyPairGenerator.initialize(
new KeyPairGeneratorSpec.Builder(context)
.setKeySize(512)
.setAlias(alias)
.setSubject(new X500Principal("CN=something"))
.setSerialNumber(BigInteger.ONE)
.setStartDate(start.getTime())
.setEndDate(end.getTime())
.build());
KeyPair keyPair = keyPairGenerator.generateKeyPair();
return keyPair.getPublic();
}
public static void signRequest(String alias, JSONObject req) throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException, UnrecoverableEntryException, InvalidKeyException, SignatureException, JSONException {
// get private key
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
KeyStore.Entry entry = keyStore.getEntry(alias, null);
PrivateKey privateKey = ((KeyStore.PrivateKeyEntry) entry).getPrivateKey();
// sign message
byte[] message = req.toString().getBytes("UTF-8");
Signature s = Signature.getInstance("SHA256withRSA");
s.initSign(privateKey);
s.update(message);
byte[] signature = s.sign();
// this doesnt work, because it changes the original message, thus preventing the server from validating the signature
req.put("signature", Base64.encodeToString(signature , Base64.DEFAULT));
}
}
public class MyClass implements Runnable {
@Override
public void run() {
URL url;
HttpURLConnection urlConnection = null;
int responseCode = -1;
try {
url = new URL("http://localhost:8080/endpoint");
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setConnectTimeout(2000);
urlConnection.setDoOutput(true);
urlConnection.setRequestMethod("POST");
urlConnection.setRequestProperty("Content-Type", "application/json");
urlConnection.setUseCaches(false);
urlConnection.connect();
//Create JSONObject here
JSONObject jsonParam = new JSONObject();
jsonParam.put("prop1", prop1);
jsonParam.put("prop2", prop2);
MyCrypto.signRequest(alias, jsonParam);
OutputStreamWriter out = new OutputStreamWriter(urlConnection.getOutputStream());
out.write(jsonParam.toString());
out.close();
responseCode = urlConnection.getResponseCode();
String response;
if (responseCode == 200) {
response = readStream(urlConnection.getInputStream());
Log.d("connection", response);
} else {
response = readStream(urlConnection.getErrorStream());
Log.d("connection", response);
}
// delegate response processing to handler
activity.handleResponse(responseCode, response);
}
catch (Exception e) {
if (responseCode == -1) {
String errorMessage = "Error connecting";
activity.handleResponse(0, errorMessage);
}
}
finally {
if(urlConnection != null)
urlConnection.disconnect();
}
}
}

您可以通过自定义标头向请求添加任何内容:

...
urlConnection.setRequestProperty("MyRSASignature", myRSASignature);
...

最新更新