@kaciocley Eu achei a solução legal, mas eu queria saber como o programa do cliente lida com este código.
Como que o programa sabe que a data é válida e não uma data longa demais criada por um usuário malicioso?
É que do jeito que vc mostrou eu entendi que vc manda o código em Base64 cru pro cliente, só que se for só isso é facinho de burlar. Se for isso mesmo, vc já teve algum caso de usuário tentando gerar o código sozinho?
Eu imaginei uma solução chaves assimétricas.
- Vc geraria as chaves publicas e privadas
- enviaria o programa pro cliente já com a chave pública
- geraria a data e a assinaria com a chave privada
- enviaria pro cliente o código no formato
<data> + <assinatura>
- o programa removeria a parte da data e verificaria a assinatura
- Se tudo correr bem, o programa abre
Seria algo assim:
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.Signature;
import java.time.LocalDate;
import java.util.Base64;
public class App {
private static final Signature signature;
private static final KeyPair keyPair;
static {
try {
final KeyPairGenerator generator = KeyPairGenerator.getInstance("DSA");
generator.initialize(2048);
keyPair = generator.generateKeyPair();
signature = Signature.getInstance("SHA256WithDSA");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
static private String getSignature(LocalDate date) throws Exception {
signature.initSign(keyPair.getPrivate());
signature.update(date.toString().getBytes());
return Base64.getEncoder().encodeToString(signature.sign());
}
static private boolean verifySignature(LocalDate date, String encodedSignature) throws Exception {
signature.initVerify(keyPair.getPublic());
signature.update(date.toString().getBytes());
return signature.verify(Base64.getDecoder().decode(encodedSignature));
}
static private String getActivationKey(LocalDate date) throws Exception {
String encodedSignature = getSignature(date);
String encodedDate = Base64.getEncoder().encodeToString(date.toString().getBytes());
return encodedDate + "." + encodedSignature;
}
public static void main(String... args) throws Exception {
LocalDate date = LocalDate.now().plusMonths(1);
String activationKey = getActivationKey(date);
System.out.println(activationKey);
// Lá no cliente:
String[] activationKeyParts = activationKey.split("\\.");
LocalDate nextDate = LocalDate.parse(new String(Base64.getDecoder().decode(activationKeyParts[0])));
if (verifySignature(nextDate, activationKeyParts[1])) {
System.out.println("A data é válida 👍🏾");
}
}
}
Será que funcionaria na prática?
EDIT 1:
Percebi que minha ideia com a assinatura na vale de nada 
Mas veja esta outra ideia onde eu mando tudo encriptado:
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.time.LocalDate;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
public class App {
private static final KeyPair keyPair;
private static final Cipher cipher;
static {
try {
final KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
generator.initialize(2048);
keyPair = generator.generateKeyPair();
cipher = Cipher.getInstance("RSA");
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
throw new RuntimeException(e);
}
}
private static String getActivationKey(LocalDate date) throws Exception {
cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPrivate());
byte[] encryptedBytes = cipher.doFinal(date.toString().getBytes());
return Base64.getEncoder().encodeToString(encryptedBytes);
}
private static LocalDate getNextExpirationDate(String activationKey) throws Exception {
cipher.init(Cipher.DECRYPT_MODE, keyPair.getPublic());
byte[] decoded = Base64.getDecoder().decode(activationKey);
return LocalDate.parse(new String(cipher.doFinal(decoded)));
}
public static void main(String... args) throws Exception {
LocalDate date = LocalDate.now().plusMonths(1);
String activationKey = getActivationKey(date);
System.out.println(activationKey);
System.out.println(getNextExpirationDate(activationKey));
}
}
EDIT 2:
Acho que a primeira ideia era válida sim, só precisei mudar um pouco o código.