New to Apple environment.
Following this guide lines https://developer.apple.com/documentation/sign_in_with_apple/sign_in_with_apple_rest_api/verifying_a_user
Trying to do "Verify the JWS E256 signature using the server’s public key" of an Apple Identity Token(JWT) which was received at iOS app during "Sign In With Apple" and was sent to Java App Server.
According to this https://developer.apple.com/forums/thread/125731
My codes are as follows -
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import org.junit.jupiter.api.Test;
import org.springframework.boot.web.client.RestTemplateBuilder;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.KeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.util.Base64;
import java.util.List;
public class AppleTest {
#Test
public void test(String appleToken) throws Exception {
AppleKeySet appleKeySet = new RestTemplateBuilder().build()
.getForObject("https://appleid.apple.com/auth/keys", AppleKeySet.class);
List<Key> applePublicKeys = appleKeySet.getKeys();
Key key = applePublicKeys.get(0);
BigInteger n = new BigInteger(1, Base64.getUrlDecoder().decode(key.getN()));
BigInteger e = new BigInteger(1, Base64.getUrlDecoder().decode(key.getE()));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
KeySpec publicKeySpec = new RSAPublicKeySpec(n, e);
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
Claims claims = Jwts.parser()
.setSigningKey(publicKey)
.parseClaimsJws(appleToken)
.getBody();
}
}
Key POJO:
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
#JsonInclude(JsonInclude.Include.NON_NULL)
public class Key {
#JsonProperty("kty")
private String kty;
#JsonProperty("kid")
private String kid;
#JsonProperty("use")
private String use;
#JsonProperty("alg")
private String alg;
#JsonProperty("n")
private String n;
#JsonProperty("e")
private String e;
}
But, I am getting JWT signature does not match locally computed signature.
I am using implementation io.jsonwebtoken:jjwt:0.9.1 for JWT.
What could be wrong?
Related
I'm trying to dynamically generate a pair of SSH keys in java, mimicking the behaviour of ssh-keygen. I intend to use those keys to communicate with an SSH server.
I have tried patching up and testing several pieces of code without success. The most recent piece of code I'm testing is this:
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
import org.bouncycastle.crypto.KeyGenerationParameters;
import org.bouncycastle.crypto.generators.Ed25519KeyPairGenerator;
import org.bouncycastle.crypto.util.OpenSSHPrivateKeyUtil;
import org.bouncycastle.crypto.util.OpenSSHPublicKeyUtil;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemWriter;
import org.junit.jupiter.api.Test;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.security.SecureRandom;
import java.security.Security;
public class GenKeysTest {
#Test
void testCase1() throws IOException {
Security.addProvider(new BouncyCastleProvider());
AsymmetricCipherKeyPairGenerator gen = new Ed25519KeyPairGenerator();
gen.init(new KeyGenerationParameters(new SecureRandom(), 255));
AsymmetricCipherKeyPair keyPair = gen.generateKeyPair();
byte[] priBytes = OpenSSHPrivateKeyUtil.encodePrivateKey(keyPair.getPrivate());
write(priBytes, "ed25519", "OPENSSH PRIVATE KEY");
byte[] pubBytes = OpenSSHPublicKeyUtil.encodePublicKey(keyPair.getPublic());
write(pubBytes, "ed25519.pub", "OPENSSH PUBLIC KEY");
}
public void write(byte[] bytes, String fileName, String type) throws IOException {
try (FileOutputStream out = new FileOutputStream(fileName)) {
try (PemWriter w = new PemWriter(new OutputStreamWriter(out))) {
w.writeObject(new PemObject(type, bytes));
}
}
}
}
I'm using the following dependencies:
dependencies {
implementation 'org.bouncycastle:bcprov-jdk15on:1.67'
implementation 'org.bouncycastle:bcpkix-jdk15on:1.67'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
}
And I'm using these command to test the resulting keys:
ssh-keygen -l -f ed25519
ssh-keygen -l -f ed25519.pub
As far as I read, those commands should output the same text line which should look like this:
256 SHA256:REDACTED user#domain.com (ED25519)
Instead the output I get from ssh-keygen is similar to this:
ed25519.pub is not a public key file.
It would be very nice if someone could point me what am I missing.
I have this test class - currently it is checking the response at the endpoint
Endpoints.SEDA_PROCESS_ENDPOINT
but I need it to check at
"mock:"+Endpoints.SEDA_PROCESS_ENDPOINT
Is there a way to forward the response to this mock endpoint I have just defined?
below is my test class
package com.sams.pricing.prism.data.processor;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import org.apache.camel.EndpointInject;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.component.mock.MockEndpoint;
import org.apache.camel.test.spring.MockEndpoints;
import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.sams.pricing.prism.data.processor.model.CostIQRetail;
import com.sams.pricing.prism.data.processor.routes.PrismRouter;
import com.sams.pricing.prism.data.processor.service.RulesEngineClient;
import com.sams.pricing.prism.data.processor.util.Endpoints;
#SpringBootTest
#CamelSpringBootTest
#MockEndpoints( Endpoints.SEDA_PROCESS_ENDPOINT)
public class CamelRouteTests3 {
#Autowired
private ProducerTemplate template;
#EndpointInject( "mock:" + Endpoints.SEDA_PROCESS_ENDPOINT)
private MockEndpoint mock;
#Mock
private PrismRouter p;
#Mock
private RulesEngineClient rulesEngineClientMock;
public CostIQRetail costIQObject() {
CostIQRetail obj = new CostIQRetail();
obj.setItemNbr(123);
obj.setLocationNbr(4931);
obj.setIsDcFlag(false) ;
obj.setStatus("SUCCESS");
obj.setOrderableCost(new BigDecimal((10.0)));
obj.setWarehousePackCost(new BigDecimal(100.0));
obj.setOrderablePrepaidCost(null) ;
obj.setOrderableCollectCost(null) ;
obj.setReasonCode("Markdown - category funded");
obj.setEffectiveDate("2022-12-29");
obj.setIsFutureEffectiveDate(false);
obj.setCostType("WAREHOUSE PACK COST");
obj.setSource("COST IQ");
obj.setCreatedBy("lab1 account");
obj.setCreatedByUserId("LB-cost-test");
obj.setCreatedTs("2022-12-29T02:42:25.529Z");
obj.setCurrentRetailPrice(new BigDecimal(55.0)) ;
obj.setCurrentOrderableCost(null);
obj.setCurrentWarehousePackCost(new BigDecimal((0.0)));
obj.setCurrentOrderablePrepaidCost(null) ;
obj.setCurrentOrderableCollectCost(null);
obj.setMarginChange(new BigDecimal((-100.0)));
obj.setOwedToClub(new BigDecimal((0.0)));
obj.setItemSourceId(3572924);
obj.setPriceDestId(701800);
obj.setCategory(87);
obj.setOrderableQty(null);
obj.setOldMargin(new BigDecimal((100.0)));
obj.setNewMargin(new BigDecimal(0.0));
return obj;
}
private String costIQPayloadString() throws JsonProcessingException
{
String key = "{\"retailTypeReasonCode\":{\"retailTypeReasonCodeId\":{\"retailType\":\"BP\",\"retailReasonCode\":\"CC\"}},\"expirationDate\":null,\"customerRetailAmount\":0.0,\"auditMessage\":null,\"createdTimestamp\":null,\"clientID\":\"COST IQ\",\"rowNumber\":0,\"auditRecordTimestamp\":null,\"clubNumber\":4931,\"itemNumber\":123,\"effectiveDate\":\"2022-12-29\",\"submissionID\":null,\"retailAmount\":55.0,\"createdBy\":\"lab1 account\"}";
String key2 = "{\"retailTypeReasonCode\":{\"retailTypeReasonCodeId\":{\"retailType\":\"BP\",\"retailReasonCode\":\"CC\"}},\"expirationDate\":null,\"customerRetailAmount\":0.0,\"auditMessage\":null,\"createdTimestamp\":null,\"clientID\":\"COST IQ\",\"rowNumber\":0,\"auditRecordTimestamp\":null,\"categoryId\":87,\"subCategoryId\":1,\"clubNumber\":4931,\"itemNumber\":123,\"effectiveDate\":\"2022-12-29\",\"submissionID\":null,\"retailAmount\":10.0,\"createdBy\":\"lab1 account\"}";
return key2;
}
#Test
void test() throws Exception {
// Set up the mock endpoints
mock.expectedBodiesReceived(costIQPayloadString());
//p.interceptSendToEndpoint( Endpoints.SEDA_PROCESS_ENDPOINT).to(mock.getEndpointUri());
Mockito.when(rulesEngineClientMock.validateRules((costIQObject()))).thenReturn(costIQObject()); //.thenR
Map<String, Object> headers = new HashMap<>();
headers.put("appName", "costIQ");
// Send the test message to the SEDA_SEND_ENDPOINT
template.sendBodyAndHeaders(Endpoints.SEDA_SEND_ENDPOINT, costIQObject(), headers);
mock.assertIsSatisfied();
}
}
I have looked at advice with but that involves adding in the cameltestsupport and would need to re-write this code. Is there a way to do this with current implementations?
As can be seen from the screenshot(https://jwt.io/) which is the expected signature, I am getting wrong java code. I am missing something very obvious wrong with code?
package com.company;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
public class Main {
public static void main(String[] args) throws InvalidKeyException, NoSuchAlgorithmException {
final Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec("qwertyuiopasdfghjklzxcvbnm123456".getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
String sourcString = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE2MjM5NTk5NDEsImV4cCI6MTY1NTQ5NTk0MSwiYXVkIjoid3d3LmV4YW1wbGUuY29tIiwic3ViIjoianJvY2tldEBleGFtcGxlLmNvbSIsIkdpdmVuTmFtZSI6IkpvaG5ueSIsIlN1cm5hbWUiOiJSb2NrZXQiLCJFbWFpbCI6Impyb2NrZXRAZXhhbXBsZS5jb20ifQ";
byte[] signatureBytes = mac.doFinal(sourcString.getBytes(StandardCharsets.UTF_8));
System.out.println("Signatured=" + Base64.getEncoder().withoutPadding().encodeToString(signatureBytes));
}
}
OUTPUT : Signatured=ZFrcK6AZzYCTs0ugepzcSFMxxuY5Fs0PtMXGDZtT3sA
http://tpcg.io/P0MtSDC3
Looks like you almost got it, since you provide the SecretKeySpec in clear text you don't have to check this check box ... or provide a clear text SecretKey that actually encodes to "qwertyuiopasdfghjklzxcvbnm123456".
I am using this java program to validate a digital signature using public key (cer file). I am using opensaml 2.6.3 jars
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.validation.Schema;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.X509EncodedKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.opensaml.DefaultBootstrap;
import org.opensaml.common.xml.SAMLSchemaBuilder;
import org.opensaml.saml2.core.NewEncryptedID;
import org.opensaml.saml2.core.Response;
import org.opensaml.xml.Configuration;
import org.opensaml.xml.XMLObject;
import org.opensaml.xml.io.Unmarshaller;
import org.opensaml.xml.io.UnmarshallerFactory;
import org.opensaml.xml.parse.BasicParserPool;
import org.opensaml.xml.security.x509.BasicX509Credential;
import org.opensaml.xml.signature.Signature;
import org.opensaml.xml.signature.SignatureValidator;
import org.opensaml.xml.validation.ValidationException;
public class FinalTester
{
public static void main(String[] args)
{
try
{
//initialize the opensaml library
DefaultBootstrap.bootstrap();
Schema schema = SAMLSchemaBuilder.getSAML11Schema();
//get parser pool manager
BasicParserPool parserPoolManager = new BasicParserPool();
parserPoolManager.setNamespaceAware(true);
parserPoolManager.setIgnoreElementContentWhitespace(true);
parserPoolManager.setSchema(schema);
////get KeyFactory object that creates key objects, specifying RSA
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
String state=
"PHNhbWxwOlJlc3BvbnNlIHhtbG5zOmFzcnQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphc3NlcnRpb24iIElzc3VlSW5zdGFudD0iMjAxNC0xMC0xN1QxODo1MTowOC4yMjE5NTk1WiIgRGVzdGluYXRpb249Imh0dHBzOi8vcWEubGV4aXNuZXhpcy5jb20vc2FtbF9zaWduaW4iIENvbnNlbnQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpjb25zZW50OnVuc3BlY2lmaWVkIiBJRD0iY2VvZGtoaW1rZW9iaWdqb2ZqZ2hmY2djZGVubW5rbXBjbW1kZnBrZyIgVmVyc2lvbj0iMi4wIiB4bWxuczpzYW1scD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnByb3RvY29sIj4NCgk8YXNydDpJc3N1ZXI+RGVsb2l0dGU8L2FzcnQ6SXNzdWVyPg0KCTxTaWduYXR1cmUgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiPg0KCQk8U2lnbmVkSW5mbz4NCgkJCTxDYW5vbmljYWxpemF0aW9uTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIiAvPg0KCQkJPFNpZ25hdHVyZU1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyNyc2Etc2hhMSIgLz4NCgkJCTxSZWZlcmVuY2UgVVJJPSIjY2VvZGtoaW1rZW9iaWdqb2ZqZ2hmY2djZGVubW5rbXBjbW1kZnBrZyI+DQoJCQkJPFRyYW5zZm9ybXM+DQoJCQkJCTxUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjZW52ZWxvcGVkLXNpZ25hdHVyZSIgLz4NCgkJCQkJPFRyYW5zZm9ybSBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMTAveG1sLWV4Yy1jMTRuIyIgLz4NCgkJCQk8L1RyYW5zZm9ybXM+DQoJCQkJPERpZ2VzdE1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyNzaGExIiAvPg0KCQkJCTxEaWdlc3RWYWx1ZT5Xc0w2QU9nbEVmWVdneE9CNmJ6YXpWN2dnZkU9PC9EaWdlc3RWYWx1ZT4NCgkJCTwvUmVmZXJlbmNlPg0KCQk8L1NpZ25lZEluZm8+DQoJCTxTaWduYXR1cmVWYWx1ZT5FZXZ2MXQ5amZ3YmZNc0h2aXRuWXFXSldBS0RkWk9zRmNLK25xei8yd1A1TjlhNGdnNTZ5YzZBMjJISnh2aUQrRjEweVhCMjVkdG5xN1Rac1BlYUNMTlpVRWRzWjJSblNpTFZjTGRVeHg2SGs1STdFcDlibTBIRG5TYVpPV0Z4N2NBTnQ2WWJzNDZLKzJ1T3JwOVdRbDVoTkFOYmo3UWNaYWdZZnZtNmQ1MVR3ZFBwZ0NxQXNWc3BkeW4zRFlaUVpKL2ZQZDZCRGNuSWN5eU1qVkU4b3lra1dCL1VRN0h3aDd6NWFwYyt4cTU0S1FOM1NWUWlLVjM2TFJXdG5SVVp3Z3hEbUEyRERTYVlRQWpGM2VMZGpBeXhsOGxMTXdTajlNVHZMdTJmSHlDMGM2ZXBudHYzSnFVZmtYNktTRHg2Vm9hdjQxaGxzaEhwMW9wNUxqZ2JMMVE9PTwvU2lnbmF0dXJlVmFsdWU+DQoJPC9TaWduYXR1cmU+DQoJPHNhbWxwOlN0YXR1cz4NCgkJPHNhbWxwOlN0YXR1c0NvZGUgVmFsdWU9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpzdGF0dXM6U3VjY2VzcyIgLz4NCgk8L3NhbWxwOlN0YXR1cz4NCgk8YXNydDpBc3NlcnRpb24gSXNzdWVJbnN0YW50PSIyMDE0LTEwLTE3VDE4OjUxOjA4LjIyMTk1OTVaIiBJRD0iZ2tma2Rub2psZ2FrbXBwcGlkaWVoYWVobWJobGVrZGNiZGhmZ2FoaCIgVmVyc2lvbj0iMi4wIj4NCgkJPGFzcnQ6SXNzdWVyPkRlbG9pdHRlPC9hc3J0Oklzc3Vlcj4NCgkJPGFzcnQ6U3ViamVjdD4NCgkJCTxhc3J0Ok5hbWVJRCBGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjEuMTpuYW1laWQtZm9ybWF0OmVtYWlsQWRkcmVzcyI+YmhnYW5kaGlAdHN0LmRlbG9pdHRlLmNvbTwvYXNydDpOYW1lSUQ+DQoJCQk8YXNydDpTdWJqZWN0Q29uZmlybWF0aW9uIE1ldGhvZD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmNtOmJlYXJlciI+DQoJCQkJPGFzcnQ6U3ViamVjdENvbmZpcm1hdGlvbkRhdGEgTm90T25PckFmdGVyPSIyMDE0LTEwLTE3VDE4OjU2OjA4LjIyMTk1OTVaIiBSZWNpcGllbnQ9Imh0dHBzOi8vcWEubGV4aXNuZXhpcy5jb20vc2FtbF9zaWduaW4iIC8+DQoJCQk8L2FzcnQ6U3ViamVjdENvbmZpcm1hdGlvbj4NCgkJPC9hc3J0OlN1YmplY3Q+DQoJCTxhc3J0OkNvbmRpdGlvbnMgTm90T25PckFmdGVyPSIyMDE0LTEwLTE3VDE4OjU2OjA4LjIyMTk1OTVaIiBOb3RCZWZvcmU9IjIwMTQtMTAtMTdUMTg6NDY6MDguMjIxOTU5NVoiPg0KCQkJPGFzcnQ6QXVkaWVuY2VSZXN0cmljdGlvbj4NCgkJCQk8YXNydDpBdWRpZW5jZT5odHRwczovL3FhLmxleGlzbmV4aXMuY29tL3NhbWxfc2lnbmluPC9hc3J0OkF1ZGllbmNlPg0KCQkJPC9hc3J0OkF1ZGllbmNlUmVzdHJpY3Rpb24+DQoJCTwvYXNydDpDb25kaXRpb25zPg0KCQk8YXNydDpBdHRyaWJ1dGVTdGF0ZW1lbnQ+DQoJCQk8YXNydDpBdHRyaWJ1dGUgTmFtZT0iRmlyc3QgTmFtZSIgTmFtZUZvcm1hdD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmF0dHJuYW1lLWZvcm1hdDpiYXNpYyI+DQoJCQkJPGFzcnQ6QXR0cmlidXRlVmFsdWUgeG1sbnM6cTE9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hIiBkNXAxOnR5cGU9InExOnN0cmluZyIgeG1sbnM6ZDVwMT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEtaW5zdGFuY2UiPkJyZW50PC9hc3J0OkF0dHJpYnV0ZVZhbHVlPg0KCQkJPC9hc3J0OkF0dHJpYnV0ZT4NCgkJCTxhc3J0OkF0dHJpYnV0ZSBOYW1lPSJMYXN0IE5hbWUiIE5hbWVGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphdHRybmFtZS1mb3JtYXQ6YmFzaWMiPg0KCQkJCTxhc3J0OkF0dHJpYnV0ZVZhbHVlIHhtbG5zOnEyPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYSIgZDVwMTp0eXBlPSJxMjpzdHJpbmciIHhtbG5zOmQ1cDE9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIj5SdWJpbzwvYXNydDpBdHRyaWJ1dGVWYWx1ZT4NCgkJCTwvYXNydDpBdHRyaWJ1dGU+DQoJCQk8YXNydDpBdHRyaWJ1dGUgTmFtZT0iRW1haWwiIE5hbWVGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphdHRybmFtZS1mb3JtYXQ6YmFzaWMiPg0KCQkJCTxhc3J0OkF0dHJpYnV0ZVZhbHVlIHhtbG5zOnEzPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYSIgZDVwMTp0eXBlPSJxMzpzdHJpbmciIHhtbG5zOmQ1cDE9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIj5iaGdhbmRoaUB0c3QuZGVsb2l0dGUuY29tPC9hc3J0OkF0dHJpYnV0ZVZhbHVlPg0KCQkJPC9hc3J0OkF0dHJpYnV0ZT4NCgkJCTxhc3J0OkF0dHJpYnV0ZSBOYW1lPSJQZXJzb25uZWxOdW1iZXIiIE5hbWVGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphdHRybmFtZS1mb3JtYXQ6YmFzaWMiPg0KCQkJCTxhc3J0OkF0dHJpYnV0ZVZhbHVlIHhtbG5zOnE0PSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYSIgZDVwMTp0eXBlPSJxNDpzdHJpbmciIHhtbG5zOmQ1cDE9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIj4wMDMwNjg2NTwvYXNydDpBdHRyaWJ1dGVWYWx1ZT4NCgkJCTwvYXNydDpBdHRyaWJ1dGU+DQoJCQk8YXNydDpBdHRyaWJ1dGUgTmFtZT0iUGVyc29uSUQiIE5hbWVGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphdHRybmFtZS1mb3JtYXQ6dW5zcGVjaWZpZWQiPg0KCQkJCTxhc3J0OkF0dHJpYnV0ZVZhbHVlIHhtbG5zOnE1PSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYSIgZDVwMTp0eXBlPSJxNTpzdHJpbmciIHhtbG5zOmQ1cDE9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIj5QZXJzb25JRDwvYXNydDpBdHRyaWJ1dGVWYWx1ZT4NCgkJCTwvYXNydDpBdHRyaWJ1dGU+DQoJCQk8YXNydDpBdHRyaWJ1dGUgTmFtZT0iTG9jYXRpb24iIE5hbWVGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphdHRybmFtZS1mb3JtYXQ6dW5zcGVjaWZpZWQiPg0KCQkJCTxhc3J0OkF0dHJpYnV0ZVZhbHVlIHhtbG5zOnE2PSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYSIgZDVwMTp0eXBlPSJxNjpzdHJpbmciIHhtbG5zOmQ1cDE9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIj4xNC8xNFMwNTNBPC9hc3J0OkF0dHJpYnV0ZVZhbHVlPg0KCQkJPC9hc3J0OkF0dHJpYnV0ZT4NCgkJPC9hc3J0OkF0dHJpYnV0ZVN0YXRlbWVudD4NCgkJPGFzcnQ6QXV0aG5TdGF0ZW1lbnQgU2Vzc2lvbkluZGV4PSJiZWNpcGxlbW5lbGRwa2JhaWhtaGhmZmVpcG5maGtwam1tYm1lYWhuIiBBdXRobkluc3RhbnQ9IjIwMTQtMTAtMTdUMTg6NTE6MDguMjIxOTU5NVoiPg0KCQkJPGFzcnQ6QXV0aG5Db250ZXh0Pg0KCQkJCTxhc3J0OkF1dGhuQ29udGV4dENsYXNzUmVmPnVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphYzpjbGFzc2VzOkludGVybmV0UHJvdG9jb2w8L2FzcnQ6QXV0aG5Db250ZXh0Q2xhc3NSZWY+DQoJCQk8L2FzcnQ6QXV0aG5Db250ZXh0Pg0KCQk8L2FzcnQ6QXV0aG5TdGF0ZW1lbnQ+DQoJPC9hc3J0OkFzc2VydGlvbj4NCjwvc2FtbHA6UmVzcG9uc2U+";
byte[] xmlString = Base64.decodeBase64(state);
String s = new String(xmlString);
Document document = parserPoolManager.parse(new ByteArrayInputStream(s.getBytes("UTF-8")));
Element metadataRoot = (Element) document.getDocumentElement();
QName qName= new QName(metadataRoot.getNamespaceURI(), metadataRoot.getLocalName(), metadataRoot.getPrefix());
// //get an unmarshaller
Unmarshaller unmarshaller = Configuration.getUnmarshallerFactory().getUnmarshaller(qName);
// //unmarshall using the document root element
Response response = (Response)unmarshaller.unmarshall(metadataRoot);
//get the signature to validate from the response object
Signature signature = response.getSignature();
/***************************************************************************************************/
//grab the certificate file
File certificateFile = new File("C:\\samlwork\\domain.com_B64.cer");
//get the certificate from the file
InputStream inputStream2 = new FileInputStream(certificateFile);
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
X509Certificate certificate = (X509Certificate)certificateFactory.generateCertificate(inputStream2);
inputStream2.close();
//pull out the public key part of the certificate into a KeySpec
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(certificate.getPublicKey().getEncoded());
//generate public key to validate signatures
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
//create credentials
BasicX509Credential publicCredential = new BasicX509Credential();
//add public key value
publicCredential.setPublicKey(publicKey);
//create SignatureValidator
SignatureValidator signatureValidator = new SignatureValidator(publicCredential);
//try to validate
try
{
signatureValidator.validate(signature);
}
catch (ValidationException ve)
{
System.out.println("Signature is NOT valid.");
System.out.println(ve.getMessage());
return;
}
//no validation exception was thrown
System.out.println("Signature is valid.");
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
}
This code if i run this in eclipse it says that the signature is valid. But if I run in RAD8.2 it says signature is invalid. Please help me with this. I am using different workspaces in rad and eclipse
I want to sign a text file (may be a .exe file or something else in the future)
using PKCS#7 and verify the signature using Java.
What do I need to know?
Where will I find an API (.jar and documentation)?
What are the steps I need to follow in order to sign data and verify the data?
Please provide me code snippet if possible.
I reckon you need the following 2 Bouncy Castle jars to generate the PKCS7 digital signature:
bcprov-jdk15on-147.jar (for JDK 1.5 - JDK 1.7)
bcmail-jdk15on-147.jar (for JDK 1.5 - JDK 1.7)
You can download the Bouncy Castle jars from here.
You need to setup your keystore with the public & private key pair.
You need only the private key to generate the digital signature & the public key to verify it.
Here's how you'd pkcs7 sign content (Exception handling omitted for brevity) :
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import org.bouncycastle.cert.jcajce.JcaCertStore;
import org.bouncycastle.cms.CMSProcessableByteArray;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.CMSSignedDataGenerator;
import org.bouncycastle.cms.CMSTypedData;
import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
import org.bouncycastle.util.Store;
import org.bouncycastle.util.encoders.Base64;
public final class PKCS7Signer {
private static final String PATH_TO_KEYSTORE = "/path/to/keyStore";
private static final String KEY_ALIAS_IN_KEYSTORE = "My_Private_Key";
private static final String KEYSTORE_PASSWORD = "MyPassword";
private static final String SIGNATUREALGO = "SHA1withRSA";
public PKCS7Signer() {
}
KeyStore loadKeyStore() throws Exception {
KeyStore keystore = KeyStore.getInstance("JKS");
InputStream is = new FileInputStream(PATH_TO_KEYSTORE);
keystore.load(is, KEYSTORE_PASSWORD.toCharArray());
return keystore;
}
CMSSignedDataGenerator setUpProvider(final KeyStore keystore) throws Exception {
Security.addProvider(new BouncyCastleProvider());
Certificate[] certchain = (Certificate[]) keystore.getCertificateChain(KEY_ALIAS_IN_KEYSTORE);
final List<Certificate> certlist = new ArrayList<Certificate>();
for (int i = 0, length = certchain == null ? 0 : certchain.length; i < length; i++) {
certlist.add(certchain[i]);
}
Store certstore = new JcaCertStore(certlist);
Certificate cert = keystore.getCertificate(KEY_ALIAS_IN_KEYSTORE);
ContentSigner signer = new JcaContentSignerBuilder(SIGNATUREALGO).setProvider("BC").
build((PrivateKey) (keystore.getKey(KEY_ALIAS_IN_KEYSTORE, KEYSTORE_PASSWORD.toCharArray())));
CMSSignedDataGenerator generator = new CMSSignedDataGenerator();
generator.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider("BC").
build()).build(signer, (X509Certificate) cert));
generator.addCertificates(certstore);
return generator;
}
byte[] signPkcs7(final byte[] content, final CMSSignedDataGenerator generator) throws Exception {
CMSTypedData cmsdata = new CMSProcessableByteArray(content);
CMSSignedData signeddata = generator.generate(cmsdata, true);
return signeddata.getEncoded();
}
public static void main(String[] args) throws Exception {
PKCS7Signer signer = new PKCS7Signer();
KeyStore keyStore = signer.loadKeyStore();
CMSSignedDataGenerator signatureGenerator = signer.setUpProvider(keyStore);
String content = "some bytes to be signed";
byte[] signedBytes = signer.signPkcs7(content.getBytes("UTF-8"), signatureGenerator);
System.out.println("Signed Encoded Bytes: " + new String(Base64.encode(signedBytes)));
}
}
PKCS#7 is known as CMS now (Cryptographic Message Syntax), and you will need the Bouncy Castle PKIX libraries to create one. It has ample documentation and a well established mailing list.
I won't supply code snippet, it is against house rules. Try yourself first.