the 2nd half of the puzzle works like this:
jo = Me
Dim privatekey As String = "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCbQxh5MndksiaO" _
& "KZjLs/Ps9DJYNQlwvQA2Qa7gf1AP4aQRdNQR1tThTH2vc2+rdveZ9rWnS+8gb3AC" _
& "AvHk5t2NQF347v3k5Lh+b/t/AQtEsUzp7kspna8vUNHZnPJpcvpWocodQcZZu9B8" _
& "iTdOiJjJxLgivTn87p9LIA4uOr15sm6hT5CB8o+rm+Q2EB0lAIUFhqcFKe/MMf0X" _
& "CyhLlGtjo/nNDf+f9bLHu0wVqmEFS5QFin3+ANvRJcYnQDxkfLWTP8Xa+ryq7xPh" _
& "2TDWf5X3keWE8/8yeEfi/fzx8pSz9zVr5VhAZ42MFE5Z+rHb3ISx0hcpZ9B3iXj1" _
& "UTJmjVkjAgMBAAECggEAPTpB6fWNYM/iZXig8V/nRx/rxJ4xuVxHO54+bPi35XNp" _
& "pJqqUNij/a8Q94Ix3O/e58ADVdSbmfJoPNrVcpvabewewt7YkA3kdbQKfUS3oWC8" _
& "AJqA2In+/k1EXClI7W2yrDxEPLJmGpf2uU3RWi6C9jqWFNkDh6vAdLtQ7Eks1FL4" _
& "tao4cdWAz23U9VqoYy1SSlUg1UVrLF0jePyp1R4YEFeqfDwHAvY6CpDocWdOAW66" _
& "YnASq5Z0wLy1jrkE8BrpMdMvss1FxgkmzJMkr53vrQ6XRTE2QqODevhvQdrCEejd" _
& "kGLkW3Cy3+rIOpqaeu5Se/dQ7nmSpYDd/LWjVKI3uQKBgQD4q4+rWyHTNQO4yl+w" _
& "sEWTLTS0JodY4BF6JWChl4Frku1KsXNOqgE2BGSiv29U6WJcDE1luwh9wU2T9/1n" _
& "4mlMy1hJ8qgUzVhIIgKHAr7FealnO7Zt/PV9c4LoEHRl/BaitLEenCbj9n+aXwsj" _
& "GmngkbmvW5Jcp1ykNbu9qQIR2QKBgQCf1q/ctjEI9pr6mZ6MBq8nFHx9oWHyjexw" _
& "wac/0U+LUY0CPqtTLnkNHc4UsYGk2lM31VExFn+oKs1rxndWRwgAEY/bDxFwFxcy" _
& "O7nTgak3hJYzc/Zv4kDatIrDtpFV18nBnDjeTj0QTBJFtaOoHjqJrNQGTCHrvK+l" _
& "kXaKdxdpWwKBgQCrwzUVk3klvjS363F1RgyIwGzrEsHibcMkr7SzaUcH2xD0yuVu" _
& "rJbxjM9Gaxyndh1un0DGyA3xbxf64Qy0OPurA7oUOfxHgh88k+FTCF5lYMfWerRj" _
& "/JpE8Qi26sa7uwiXkl/VWN60D4vMQWIb+R6w83di3MmYHjIrasInGxpG4QKBgQCF" _
& "9tnOkqTmbknWX4qSscd7aaAta2U8ddcFaklTI4sXqXIVv5C4Vur+I0zl6yBNmu7E" _
& "jPVPvxufRsCE5AKBPWdnJ1D6uNZUrAW1BHnq23GIJof89+REQc05gLgM8Kc+220t" _
& "6FGBgPGNBzUJWAOilDNb0I6j+Is1mR9eFVzVEJt+oQKBgQC8Fs7az7mhv00ffxAD" _
& "ehc2w9KS7vrF9FVSSiFzv+QtaHCHnGrQMepAomk8DHfT4g+FJIJyZLs89qFugTYR" _
& "aozcVkxASaPkx8TljYLRs7oKu68+JyCLxlAJRuw8qO9PV0fYiqurOWBdspVmjcBl" _
& "4vP0nmpHoNfeaJMY8PF/cB2hzA=="
jo.RunMethod("getSignedText", Array("SOME_NORMALIZED_TEXT",Null,privatekey))
' in case you get an "algorithn not found error", this call below will tell
' you what's available on your computer.
' jo.RunMethod("whatsAvailable",Null)
then:
#if Java
import java.security.Signature;
import java.util.Base64;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.KeyFactory;
import java.util.Arrays;
import java.security.Provider.Service;
public static String getSignedText(String text, String algorithm, String privateKey) {
try {
// convert privateKey string to PrivateKey.class
byte[] clear = Base64.getDecoder().decode(privateKey.getBytes());
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(clear);
KeyFactory fact = KeyFactory.getInstance("RSA");
PrivateKey priv = fact.generatePrivate(keySpec);
Arrays.fill(clear, (byte) 0);
byte[] data = text.getBytes("UTF8");
Signature sig = Signature.getInstance(algorithm == null ? "SHA256withRSA" : algorithm);
sig.initSign(priv);
sig.update(data);
byte[] signatureBytes = sig.sign();
String retString = Base64.getEncoder().encodeToString(signatureBytes);
BA.Log(retString);
return(retString);
}
catch(Exception e) {
BA.Log(e.toString());
return(e.toString());
}
}
import java.util.TreeSet;
import java.security.Security;
import java.security.Provider;
public static void whatsAvailable() {
TreeSet<String> algorithms = new TreeSet<>();
for (Provider provider : Security.getProviders())
for (Service service : provider.getServices())
if (service.getType().equals("Signature"))
algorithms.add(service.getAlgorithm());
for (String algorithm : algorithms)
BA.Log(algorithm);
}
#End If
notes:
1) this line of java code you originally posted is wrong:
there is no space before SHA256WITHRSA (" SHA256WITHRSA"), and "SHA256WITHRSA" itself is SHA256withRSA
2) your private key is a string which has to be converted to an instance of PrivateKey before it can be signed
3) your private key does includes the header and trailer. they have to be stripped before using the key for signing. i did that in the b4j code. but it could be done in the inline java.
4) the result is "similar" to what you're looking for. where what you're expecting has "#"'s, my version has "+". i don't know why the difference, but it is simple enough to subsititue "#" for "+" in the result (assuming the rest was what you're expecting).
when i ran the code with a random string, i got: L+0Kka+ALrt8ues2lAx2Ad+MVjbGfRJ8cOKtPTM5sC46wG1aUbWkMQHUDZbT9bwYGF+isemhncbkcL+SS4GKuPyVOX5AR7rfX44br+GP/eZFzQwFvwJDtjoCY5vm6cpKyLwbKiynNUttEoqYQGf1qfhJXFtxH2As1F4rcRbfM/pFmJtELgGTKotYhjZZnZQ7lPPOT/URGn3VUBuOUzFl9laiJbiYow/TvzZT1iK/f2mX94yd9yPczSI24alSHLkwJgfhiBqSON+9XPFnUH+BNsbK/YrDIp6BCW+lIFwTPUhYJTcuaghQqLm9hJQZ/vSUHeu6RP2PYFSWIU6R3eSzgg==
also, your expected output is a hex string. what i got using the code snippet you posted is base64. i don't know if there is a missing step in the snippet. since there was already an error in one line, i suppose it's possible.
5) not all algorithms are supported on all devices and in all versions of java. in such occasions, you get an exception, eg, "algorithm not found..." before i noticed the error in the snippet, i got that exception. in order to know which algorithms a device supports, i added another inline routine. if you run it, it spits out a list of all the algorithms supported on your device. when i ran it, i got a list:
MD2withRSA
MD5andSHA1withRSA
MD5withRSA
NONEwithDSA
NONEwithECDSA
NONEwithRSA
SHA1withDSA
SHA1withECDSA
SHA1withRSA
SHA224withDSA
SHA224withECDSA
SHA224withRSA
SHA256withDSA
SHA256withECDSA
SHA256withRSA
SHA384withECDSA
SHA384withRSA
SHA512withECDSA
SHA512withRSA
when i saw "SHA256withRSA", i realized there was a misspelling in the java snippet.
anyway, plug the 2 snippets posted above into your b4j code and see what you get when you use your private key