I'm trying to make use of Java signatures in a pretty time sensitive setting.
I've come across some interesting behavior when signing data of a few hundred bytes. I am reusing a generated key, but recreating the Signature object each time I sign. The first time the signing happens it takes from anywhere from 50-100ms depending on the machine being used. However, any subsequent times a signature is computed over new data (using the same key) the time is reduced down to 1-2ms. I'm using SHA512 with RSA so I expected it to be heavier.
Can anyone explain why this happens? A test class I am using is pasted below (which is using identical code to my target applictaion).
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.Signature;
public class MainClass {
public static void main(String args[]) throws Exception {
//Generate key pair
long start = System.currentTimeMillis();
KeyPair keyPair = generateKeyPair(999);
long end = System.currentTimeMillis();
System.out.println("KeyGen: " + (end - start));
//Sign first piece of data
byte[] data = { ** a few hundred bytes** };
start = System.currentTimeMillis();
byte[] digitalSignature = signData(data, keyPair.getPrivate());
end = System.currentTimeMillis();
System.out.println("Sign: " + (end - start));
boolean verified;
byte[] data2 = {** a different few hundred bytes ** };
//sign second piece of data
start = System.currentTimeMillis();
digitalSignature = signData(data2, keyPair.getPrivate());
end = System.currentTimeMillis();
System.out.println(" Second Sign: " + (end - start));
//verify second signature
start = System.currentTimeMillis();
verified = verifySig(data2, keyPair.getPublic(), digitalSignature);
end = System.currentTimeMillis();
System.out.println("Verify: " + (end - start));
System.out.println(verified);
}
public static byte[] signData(byte[] data, PrivateKey key) throws Exception {
Signature signer = Signature.getInstance("SHA512withRSA");
signer.initSign(key);
signer.update(data);
return (signer.sign());
}
public static boolean verifySig(byte[] data, PublicKey key, byte[] sig) throws Exception {
Signature signer = Signature.getInstance("SHA512withRSA");
signer.initVerify(key);
signer.update(data);
return (signer.verify(sig));
}
public static KeyPair generateKeyPair(long seed) throws Exception {
KeyPairGenerator keyGenerator = KeyPairGenerator.getInstance("RSA");
SecureRandom rng = SecureRandom.getInstance("SHA1PRNG", "SUN");
rng.setSeed(seed);
keyGenerator.initialize(1024, rng);
return (keyGenerator.generateKeyPair());
}
}
This results in the output (time in ms)
KeyGen: 81
Sign: 52
Second Sign: 2
Verify: 2
I put some benchmarks on each line of the sign method, and it appears the overhead is purely from the sign action itself.
Create Sig Obj: 1
Init sign: 1
update: 0
Sign: 49
Create Sig Obj: 1
Init sign: 0
update: 0
Second Sign: 2
Any insight would be much appreciated
Related
I am fetching datetime from an Oracle database and parsing in Java 11 using ZonedDateTime as below:
Oracle --> 1/19/2020 06:09:46.038631 PM
Java ZonedDateTime output --> 2020-01-19T18:09:46.038631Z[UTC]
Oracle --> 1/19/2011 4:00:00.000000 AM
Java ZonedDateTime output --> 2011-01-19T04:00Z[UTC] (So, here the 0s are truncated by default.
However, my requirement is to have consistent fixed length output like #1.)
Expected Java ZonedDateTime output --> 2011-01-19T04:00:00.000000Z[UTC]
However, I didn’t find any date API methods to achieve above expected output. Instead of manipulating a string, is there a way to preserve the trailing 0s with fixed length?
We have consistent ZonedDateTime types in the application, so we do not prefer to change that.
We have consistent ZonedDateTime type in application, so we do not
prefer to change that.
Why do you think 2011-01-19T04:00Z[UTC] is inconsistent? A date-time object is supposed to hold (and provide methods/functions to operate with) only the date, time, and time-zone information. It is not supposed to store any formatting information; otherwise, it will violate the Single-responsibility principle. The formatting should be handled by a formating class e.g. DateTimeFormatter (for modern date-time API), DateFormat (for legacy java.util date-time API) etc.
Every class is supposed to override the toString() function; otherwise, Object#toString will be returned when its object will be printed. A ZonedDateTime has date, time and time-zone information. Given below is how its toString() for time-part has been implemented:
#Override
public String toString() {
StringBuilder buf = new StringBuilder(18);
int hourValue = hour;
int minuteValue = minute;
int secondValue = second;
int nanoValue = nano;
buf.append(hourValue < 10 ? "0" : "").append(hourValue)
.append(minuteValue < 10 ? ":0" : ":").append(minuteValue);
if (secondValue > 0 || nanoValue > 0) {
buf.append(secondValue < 10 ? ":0" : ":").append(secondValue);
if (nanoValue > 0) {
buf.append('.');
if (nanoValue % 1000_000 == 0) {
buf.append(Integer.toString((nanoValue / 1000_000) + 1000).substring(1));
} else if (nanoValue % 1000 == 0) {
buf.append(Integer.toString((nanoValue / 1000) + 1000_000).substring(1));
} else {
buf.append(Integer.toString((nanoValue) + 1000_000_000).substring(1));
}
}
}
return buf.toString();
}
As you can see, the second and nano parts are included in the returned string only when they are greater than 0. It means that you need to use a formatting class if you want these (second and nano) zeros in the output string. Given below is an example:
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
String input = "1/19/2011 4:00:00.000000 AM";
// Formatter for input string
DateTimeFormatter inputFormatter = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.appendPattern("M/d/u H:m:s.n a")
.toFormatter(Locale.ENGLISH);
ZonedDateTime zdt = LocalDateTime.parse(input, inputFormatter).atZone(ZoneOffset.UTC);
// Print `zdt` in default format i.e. the string returned by `zdt.toString()`
System.out.println(zdt);
// Formatter for input string
DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.nnnnnnz");
String output = zdt.format(outputFormatter);
System.out.println(output);
}
}
Output:
2011-01-19T04:00Z
2011-01-19T04:00:00.000000Z
Food for thought:
public class Main {
public static void main(String[] args) {
double d = 5.0000;
System.out.println(d);
}
}
What output do you expect from the code given above? Does 5.0 represent a value different from 5.0000? How will you print 5.0000? [Hint: Check String#format, NumberFormat, BigDecimal etc.]
I am using ESAPI Base64 encryption and decryption shown as is in:
http://www.programcreek.com/java-api-examples/index.php?api=org.owasp.esapi.codecs.Base64
This is how my code looks:
import org.owasp.esapi.crypto.CipherText;
import org.owasp.esapi.crypto.PlainText;
import org.owasp.esapi.errors.EncryptionException;
import org.owasp.esapi.reference.crypto.JavaEncryptor;
import javax.crypto.EncryptedPrivateKeyInfo
import org.owasp.esapi.ESAPI
import org.owasp.esapi.ValidationErrorList
import org.owasp.esapi.Validator
import org.apache.commons.codec.binary.Base64;
class SampleMain {
public String decrypt2(String cryptedText){
String clearText=null;
try {
CipherText cipherText=CipherText.fromPortableSerializedBytes(Base64.decodeBase64(cryptedText));
clearText=ESAPI.encryptor().decrypt(cipherText).toString();
}
catch ( EncryptionException e) {
System.out.println("EsapiEncryptor.decrypt: " + e.getMessage(),e);
}
return clearText.toString();
}
public String encrypt2(String clearText){
String cryptedText=null;
try {
CipherText cipherText=ESAPI.encryptor().encrypt(new PlainText(clearText));
cryptedText=Base64.encodeBase64(cipherText.asPortableSerializedByteArray());
}
catch ( EncryptionException e) {
System.out.println("EsapiEncryptor.encrypt: " + e.getMessage(),e);
}
return cryptedText;
}
public static void main(String[] args) throws EncryptionException{
String myplaintext = "MyPlaintext";
SampleMain sample = new SampleMain();
String enString = sample.encrypt2(myplaintext);
System.out.println("-----------enString-----------: " + enString);
String deString = sample.decrypt2(enString);
System.out.println("-----------deString-----------: " + deString);
}
}
But when I try to run this simple program i get the following exception:
Apr 01, 2017 12:43:30 PM org.owasp.esapi.reference.JavaLogFactory$JavaLogger log
WARNING: [SECURITY FAILURE Anonymous:null#unknown -> /DefaultName/IntrusionDetector] Likely tampering with KDF version on serialized ciphertext.KDF version read from serialized ciphertext (123190483) is out of range. Valid range for KDF version is [20110203, 99991231].
org.owasp.esapi.errors.EncryptionException: Version info from serialized ciphertext not in valid range.
at org.owasp.esapi.crypto.CipherTextSerializer.convertToCipherText(CipherTextSerializer.java:299)
at org.owasp.esapi.crypto.CipherTextSerializer.<init>(CipherTextSerializer.java:80)
at org.owasp.esapi.crypto.CipherText.fromPortableSerializedBytes(CipherText.java:176)
at org.owasp.esapi.crypto.CipherText$fromPortableSerializedBytes$0.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
at gov.gsa.dss.test.SampleMain.decrypt2(SampleMain.groovy:30)
at gov.gsa.dss.test.SampleMain$decrypt2$0.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
at gov.gsa.dss.test.SampleMain.main(SampleMain.groovy:59)
Any ideas why I would be getting this error or such a simple program. Thanks.
This works for me:
public String decrypt2(String encryptedText) {
byte[] encryptedTextTextAsBytes = encryptedText.getBytes(StandardCharsets.UTF_8)
CipherText cipherText = CipherText.fromPortableSerializedBytes(Base64.decodeBase64(encryptedTextTextAsBytes))
ESAPI.encryptor().decrypt(cipherText).toString()
}
public String encrypt2(String clearText) {
CipherText cipherText = ESAPI.encryptor().encrypt(new PlainText(clearText))
new String(Base64.encodeBase64(cipherText.asPortableSerializedByteArray()), StandardCharsets.UTF_8)
}
You are passing a String to Base64.decodeBase64(), it might compile but I'm not sure of what Groovy does with that. You should pass a bytes[] (see how I obtain encryptedTextTextAsBytes). It might explain your error, it might not. I guess you did not post the exact code that produces the error you mention.
My web application is using Apache CXF and JAVA8, and facing below error in response if user send xs:datetime input(seconds 00) as
<urn1:dateTimeVal>2016-04-29T20:00:00</urn1:dateTimeVal>
ERROR :
org.apache.cxf.interceptor.Fault: Marshalling Error:
cvc-datatype-valid.1.2.1: '2016-04-29T20:00' is not a valid value for
'dateTime'.
I debug and analysed that if user send dateTimeVal as 2016-04-29T20:00:00 then CXF validations for input are passed and XML value is UnMarshaled to java.time.LocalDateTime as 2016-05-05T20:00 , and at the time of returning the response, the Marshaling error occurs due to loss of seconds part(00).
Any help/hint are appreciated.
P.S : You can try with below snippet :
java.time.LocalDateTime dt= java.time.LocalDateTime.of(2016, Month.MAY, 5, 20, 00, 00);
System.out.println(dt);
Note : Above code sample is just for understanding to print datetime value. But actual return type expected in web application is java.time.LocalDateTime
OUTPUT EXPECTED : 2016-05-05T20:00:00
OUTPUT ACTUAL : 2016-05-05T20:00
EDIT : The binding (JAXB) content for the field is :
#XmlElement(required = true, type = String.class)
#XmlJavaTypeAdapter(LocalDateTimeAdapter.class)
#XmlSchemaType(name = "dateTime")
#Generated(value = "com.sun.tools.xjc.Driver", date = "2016-05-03T05:28:57+05:30", comments = "JAXB RI v2.2.11")
#NotNull
protected LocalDateTime dateTimeVal;
AND LocalDateTimeAdapter File is
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.temporal.TemporalAccessor;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class LocalDateTimeAdapter
extends XmlAdapter<String, LocalDateTime>
{
public static LocalDateTime parse(String value)
{
DateTimeFormatter dateTimeAndZoneformatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
DateTimeFormatter dateTimeformatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
TemporalAccessor ta = null;
try
{
ta = dateTimeformatter.parse(value);
}
catch (DateTimeParseException ex)
{
ta = dateTimeAndZoneformatter.parse(value);
}
return LocalDateTime.from(ta);
}
public static String print(LocalDateTime value)
{
return value.toString();
}
public LocalDateTime unmarshal(String value)
{
return parse(value);
}
public String marshal(LocalDateTime value)
{
return print(value);
}
}
The problem appears to be in LocalDateTimeAdapter.print(). LocalDateTime.toString() omits the seconds when the seconds value is 0.
If you change it to
public static String print(LocalDateTime value)
{
return value.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
}
it will provide the seconds as well when marshaling.
To see a quick example, note the results of the following snippet:
System.out.println(LocalDateTime.of(2016,1,1,0,0,0,0).toString());
System.out.println(LocalDateTime.of(2016,1,1,0,0,0,0).format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
The output it gives is
2016-01-01T00:00
2016-01-01T00:00:00
In the documentation for LocalDateTime.toString() it explains this behavior:
The output will be one of the following ISO-8601 formats:
- uuuu-MM-dd'T'HH:mm
- uuuu-MM-dd'T'HH:mm:ss
- uuuu-MM-dd'T'HH:mm:ss.SSS
- uuuu-MM-dd'T'HH:mm:ss.SSSSSS
- uuuu-MM-dd'T'HH:mm:ss.SSSSSSSSS
The format used will be the shortest that outputs the full value of the time where the omitted parts are implied to be zero.
You may want to use
System.out.println (DateTimeFormatter.ISO_LOCAL_DATE_TIME.format (dt));
It gives:
2016-05-05T20:00:00
Can someone point me to the preferred method for generating a report or document ID? I have been looking at maybe using a guid that would be reduced down to a shorter length. We have an application that creates an ID for reports that is about 8 characters long. They appear to be using some type of hash code. Probably using a base 36 encoding scheme. But I cant seem to find a way to make the hash code come out to a length of 8 characters since people have to use them to refer to the documents. They would also be used in a disconnected environment, so you couldnt look up the next usable serialized number in the chain. Just wondering what some of you use in applications like this?
The .net Framwork provides RNGCryptoServiceProvider class which Implements a cryptographic Random Number Generator (RNG) using the implementation provided by the cryptographic service provider (CSP). This class is usually used to generate random numbers. Although I can use this class to generate unique number in some sense but it is also not collision less. Moreover while generating key we can make key more complicated by making it as alpha numeric rather than numeric only. So, I used this class along with some character masking to generate unique key of fixed length.
private string GetUniqueKey()
{
int maxSize = 8 ;
int minSize = 5 ;
char[] chars = new char[62];
string a;
a = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
chars = a.ToCharArray();
int size = maxSize ;
byte[] data = new byte[1];
RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider();
crypto.GetNonZeroBytes(data) ;
size = maxSize ;
data = new byte[size];
crypto.GetNonZeroBytes(data);
StringBuilder result = new StringBuilder(size) ;
foreach(byte b in data )
{ result.Append(chars[__b % (chars.Length - )>); }
<span class="code-keyword">return result.ToString();
}
http://www.codeproject.com/Articles/14403/Generating-Unique-Keys-in-Net
This is what I ended up using. It is a base36 encoding. I borrowed parts of the code from other people, so I cant claim that I wrote it all, but I hope this helps others. This will produce about a 12 digit record ID, or unique ID for databases etc. It uses only the last 2 digits of the year, so it should be good for 100 years.
using System;
using System.Collections.Generic;
using System.Windows.Forms;
namespace Base36Converter
{
public partial class Form1 : Form
{
private const string CharList = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
public Form1()
{
InitializeComponent();
}
//Base 36 number consists of only numbers and uppercase letters only.
private void button1_Click(object sender, EventArgs e)
{
if (textBox2.Text.Length > 0)
{
label3.Text = "";
//Get Date and Time Stamp
string temp1 = GetTimestamp(DateTime.Now);
//Turn it into a long number
long l = Convert.ToInt64(temp1);
//Now encode it as a base36 number.
string s1 = Encode(l);
//Get userID as a number, i.e. 1055 (User's index number) and create as a long type.
long l1 = Convert.ToInt64(textBox2.Text);
//Encode it as a base36 number.
string s2 = Encode(l1);
//Now display it as the encoded user number + datetime encoded number (Concatenated)
textBox1.Text = s2 + s1;
}
else
{
label3.Text = "User Number must be greater than 0. ie 1055";
}
}
public static String Encode(long input)
{
if (input < 0) throw new ArgumentOutOfRangeException("input", input, "input cannot be negative");
char[] clistarr = CharList.ToCharArray();
var result = new Stack<char>();
while (input != 0)
{
result.Push(clistarr[input % 36]);
input /= 36;
}
return new string(result.ToArray());
}
public static String GetTimestamp(DateTime value)
{
return value.ToString("yyMMddHHmmssffff");
}
private void Form1_Load(object sender, EventArgs e)
{
label3.Text = "";
}
}
}
I came up with the following code to calculate the factorial of a given number:
import java.lang.*;
import java.math.*;
import java.io.*;
import java.util.*;
#SuppressWarnings("unused")
class factorial_1{
public static void main(String args[]) throws IOException
{
System.out.println("enter a number: ");
String strPhone = "";
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
strPhone = br.readLine();
BigInteger number = new BigInteger (strPhone);
BigInteger fact = new BigInteger("1");
BigInteger i = new BigInteger("1");
BigInteger step = new BigInteger("1");
final long start = System.currentTimeMillis();
final long durationInMilliseconds = System.currentTimeMillis()-start;
for ( ; i.compareTo(number) <= 0; i=i.add(step)){
fact = fact.multiply(i);
}
System.out.println("execute Long-Running Task took " + durationInMilliseconds + "ms.");
System.out.println("the factorial of "+ number +" is "+ fact);
}
}
if you execute the code, it reads a number from the keyboard and then
prints out its factorial
I exported the code as a .jar file and tried to give the number (10) as input, from the terminal
I did as this post says How to execute jar with command line arguments but nothing happened until I typed again the number
-----------Terminal-----------
roditis#NiSLab-pc2:~/Desktop$ java -jar import_number.jar 10
enter a number:
10
execute Long-Running Task took 0ms.
the factorial of 10 is 3628800
-----------Terminal-----------
Im new to linux / programming and I really look forward for your help
Thanks in advance
Roditis
You should try putting the value in quotes like roditis#NiSLab-pc2:~/Desktop$ java -jar import_number.jar "10"
Remember that your main function takes an array of String objects like so public static void main(String[] args).
EDIT
Sorry, I see that you are not reading the args[] parameter at all. If you provide "10" as an argument to your program, then args[0] will contain that value. Please check if(args.length >= 1) in your case before accessing args.