La seguridad de un software no es un software de seguridad. Nos preocupamos de cuestiones como la autenticación, el control de acceso, la confidencialidad, la criptografía y la gestión de privilegios.
...
DSA dsa = new DSACryptoServiceProvider(1024);
...
...
DSA_generate_parameters_ex(dsa, 1024, NULL, 0, NULL, NULL, NULL);
...
...
dsa.GenerateParameters(params, rand.Reader, dsa.L1024N160)
privatekey := new(dsa.PrivateKey)
privatekey.PublicKey.Parameters = *params
dsa.GenerateKey(privatekey, rand.Reader)
...
...
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA", "SUN");
SecureRandom random = SecureRandom.getInstance("SHA256PRNG", "SUN");
keyGen.initialize(1024, random);
...
...
from Crypto.PublicKey import DSA
key = DSA.generate(1024)
...
require 'openssl'
...
key = OpenSSL::PKey::DSA.new(1024)
...
EVP_SignUpdate
, lo que producirá la creación de una firma basada en ningún dato:
...
rv = EVP_SignInit(ctx, EVP_sha512());
...
rv = EVP_SignFinal(ctx, sig, &sig_len, key);
...
update
, lo que producirá la creación de una firma basada en ningún dato:
...
Signature sig = Signature.getInstance("SHA256withRSA");
sig.initSign(keyPair.getPrivate());
...
byte[] signatureBytes = sig.sign();
...
...
DSA dsa1 = new DSACryptoServiceProvider(Convert.ToInt32(TextBox1.Text));
...
key_len
e incluso en esos casos debe existir una protección adecuada para comprobar que sea un valor numérico y que esté dentro de un rango de valores adecuado para un tamaño de clave. En la mayoría de los casos de uso, este debe ser un número con codificación rígida lo suficientemente alta.
...
dsa.GenerateParameters(params, rand.Reader, key_len)
privatekey := new(dsa.PrivateKey)
privatekey.PublicKey.Parameters = *params
dsa.GenerateKey(privatekey, rand.Reader)
...
key_len
. En estos casos, debe verificar tanto que sea un valor numérico como que se encuentre en un intervalo de valores adecuado para el tamaño de clave. Para la mayoría de los casos de uso, seleccione un tamaño de clave codificada de forma rígida lo suficientemente grande.
require 'openssl'
...
key_len = io.read.to_i
key = OpenSSL::PKey::DSA.new(key_len)
...
key_len
e incluso en esos casos debe existir una protección adecuada para comprobar que sea un valor numérico y que esté dentro de un rango de valores adecuado para un tamaño de clave. En la mayoría de los casos de uso, este debe ser un número con codificación rígida lo suficientemente alta.Ejemplo 2: El siguiente código deshabilita la validación segura de la firma XML con
Properties props = System.getProperties();
...
properties.setProperty("org.jcp.xml.dsig.secureValidation", "false");
XMLCryptoContext.setProperty
:
DOMCryptoContext cryptoContext = new DOMCryptoContext() {...};
...
cryptoContext.setProperty("org.jcp.xml.dsig.secureValidation", false);
...
CCCrypt(kCCEncrypt,
kCCAlgorithmDES,
kCCOptionPKCS7Padding,
key,
kCCKeySizeDES, // 64-bit key size
iv,
plaintext,
sizeof(plaintext),
ciphertext,
sizeof(ciphertext),
&numBytesEncrypted);
...
...
let iv = getTrueRandomIV()
...
let cStatus = CCCrypt(UInt32(kCCEncrypt),
UInt32(kCCAlgorithmDES),
UInt32(kCCOptionPKCS7Padding),
key,
keyLength,
iv,
plaintext,
plaintextLength,
ciphertext,
ciphertextLength,
&numBytesEncrypted)
...
String
puede suponer una pérdida significativa de entropía.String
.String
.
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
...
KeyGenerator keygen = KeyGenerator.newInstance("AES");
...
SecretKey cryptoKey = keygen.generateKey();
byte[] rawCryptoKey = cryptoKey.getEncoded();
...
String key = new String(rawCryptoKey);
...
String
utilizando el conjunto de caracteres del sistema predeterminado. Sin embargo, no se especifica lo que ocurre cuando se da al constructor bytes fuera del rango válido de este conjunto de caracteres. De esta forma, key
ocasionará una pérdida significativa de entropía en comparación con la clave de cifrado original rawCryptoKey
.
static public byte[] EncryptWithRSA(byte[] plaintext, RSAParameters key) {
try {
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.ImportParameters(key);
return rsa.Encrypt(plaintext, false);
}
catch(CryptographicException e) {
Console.WriteLine(e.Message);
return null;
}
}
void encrypt_with_rsa(BIGNUM *out, BIGNUM *in, RSA *key) {
u_char *inbuf, *outbuf;
int ilen;
...
ilen = BN_num_bytes(in);
inbuf = xmalloc(ilen);
BN_bn2bin(in, inbuf);
if ((len = RSA_public_encrypt(ilen, inbuf, outbuf, key, RSA_NO_PADDING)) <= 0) {
fatal("encrypt_with_rsa() failed");
}
...
}
...
import "crypto/rsa"
...
plaintext := []byte("Attack at dawn")
cipherText, err := rsa.EncryptPKCS1v15(rand.Reader, &k.PublicKey, plaintext)
...
public Cipher getRSACipher() {
Cipher rsa = null;
try {
rsa = javax.crypto.Cipher.getInstance("RSA/NONE/NoPadding");
}
catch (java.security.NoSuchAlgorithmException e) {
log("this should never happen", e);
}
catch (javax.crypto.NoSuchPaddingException e) {
log("this should never happen", e);
}
return rsa;
}
+ (NSData *) encryptData:(NSData *) plaintextData withKey:(SecKeyRef *) publicKey {
CFErrorRef error = nil;
NSData *ciphertextData = (NSData*) CFBridgingRelease(
SecKeyCreateEncryptedData(*publicKey,
kSecKeyAlgorithmRSAEncryptionPKCS1,
(__bridge CFDataRef) plaintextData,
&error));
if (error) {
// handle error ...
}
return ciphertextData;
}
function encrypt($input, $key) {
$output='';
openssl_public_encrypt($input, $output, $key, OPENSSL_NO_PADDING);
return $output;
}
...
from Crypto.PublicKey import RSA
message = 'Attack at dawn'
key = RSA.importKey(open('pubkey.der').read())
ciphertext = key.encrypt(message)
...
require 'openssl'
...
key = OpenSSL::PKey::RSA.new 2048
public_encrypted = key.public_encrypt(data) #padding type not specified
...
Example 1
, OpenSSL::PKey::RSA#public_encrypt
solo se llama con una cadena y no especifica el tipo de relleno a utilizar. El relleno se establece de forma predeterminada en OpenSSL::PKey::RSA::PKCS1_PADDING
.
func encrypt(data plaintextData:Data, publicKey:SecKey) throws -> Data {
var error: Unmanaged<CFError>?
guard let ciphertextData = SecKeyCreateEncryptedData(publicKey,
.rsaEncryptionPKCS1,
plaintextData as CFData,
&error) else {
throw error!.takeRetainedValue() as Error
}
return ciphertextData as Data;
}
...
Blob iv = Blob.valueOf('1234567890123456');
Blob encrypted = Crypto.encrypt('AES128', encKey, iv, input);
...
byte[] iv = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
using (SymmetricAlgorithm aesAlgo = SymmetricAlgorithm.Create("AES"))
{
...
aesAlgo.IV = iv;
...
}
unsigned char * iv = "12345678";
EVP_EncryptInit_ex(&ctx, EVP_idea_gcm(), NULL, key, iv);
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
)
...
block, err := aes.NewCipher(key)
...
mode := cipher.NewCBCEncrypter(block, key)
mode.CryptBlocks(ciphertext[aes.BlockSize:], plaintext)
byte[] iv = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
IvParameterSpec ips = new IvParameterSpec(iv);
...
const iv = "hardcoded"
const cipher = crypto.createCipheriv("aes-192-ccm", key, iv)
...
NSString *iv = @"1234567812345678"; //Bad idea to hard code IV
char ivPtr[kCCBlockSizeAES128];
[iv getCString:ivPtr maxLength:sizeof(ivPtr) encoding:NSASCIIStringEncoding];
...
ccStatus = CCCrypt( kCCEncrypt,
kCCAlgorithmAES128,
kCCOptionPKCS7Padding,
[key cStringUsingEncoding:NSASCIIStringEncoding],
kCCKeySizeAES128,
[ivPtr], /*IV should be something random (not null and not constant)*/
[self bytes], dataLength, /* input */
buffer, bufferSize, /* output */
&numBytesEncrypted
);
nil
) se utilizará entonces un IV de todos los ceros.
from Crypto.Cipher import AES
from Crypto import Random
...
key = Random.new().read(AES.block_size)
cipher = AES.new(key, AES.MODE_CTR, IV=key)
require 'openssl'
...
cipher = OpenSSL::Cipher::AES.new('256-GCM')
cipher.encrypt
@key = cipher.random_key
cipher.iv=@key
encrypted = cipher.update(data) + cipher.final # encrypts data without hardcoded IV
...
...
let cStatus = CCCrypt(UInt32(kCCEncrypt),
UInt32(kCCAlgorithmAES128),
UInt32(kCCOptionPKCS7Padding),
key,
keyLength,
"0123456789012345",
plaintext,
plaintextLength,
ciphertext,
ciphertextLength,
&numBytesEncrypted)
nil
) se utilizará entonces un IV de todos los ceros.
...
var objAesCryptoService = new AesCryptoServiceProvider();
objAesCryptoService.Mode = CipherMode.ECB;
objAesCryptoService.Padding = PaddingMode.PKCS7;
objAesCryptoService.Key = securityKeyArray;
var objCrytpoTransform = objAesCryptoService.CreateEncryptor();
...
EVP_EncryptInit_ex(&ctx, EVP_aes_256_ecb(), NULL, key, iv);
...
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
ciphertext := make([]byte, aes.BlockSize+len(plaintext))
iv := ciphertext[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(ciphertext[aes.BlockSize:], plaintext)
...
...
SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
cipher.init(Cipher.ENCRYPT_MODE, key);
...
...
ccStatus = CCCrypt( kCCEncrypt,
kCCAlgorithmAES,
kCCOptionECBMode, // Uses ECB mode
key,
kCCKeySizeAES128,
iv,
plaintext,
sizeof(plaintext),
ciphertext,
sizeof(ciphertext),
&numBytesEncrypted);
...
from Crypto.Cipher import AES
from Crypto import Random
...
key = Random.new().read(AES.block_size)
random_iv = Random.new().read(AES.block_size)
cipher = AES.new(key, AES.MODE_ECB, random_iv)
require 'openssl'
...
cipher = OpenSSL::Cipher::AES.new('256-ECB')
...
ccStatus = CCCrypt(UInt32(kCCEncrypt),
UInt32(kCCAlgorithmAES128),
UInt32(kCCOptionECBMode),
keyData.bytes,
keyLength,
keyData.bytes,
data.bytes,
data.length,
cryptData.mutableBytes,
cryptData.length,
&numBytesEncrypted)
...
static public byte[] EncryptWithRSA(byte[] plaintext, RSAParameters key) {
try {
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(512);
rsa.ImportParameters(key);
return rsa.Encrypt(plaintext, true);
}
catch(CryptographicException e) {
Console.WriteLine(e.Message);
return null;
}
}
EVP_PKEY * get_RSA_key() {
unsigned long err;
EVP_PKEY * pkey;
RSA * rsa;
rsa = RSA_generate_key(512, 35, NULL, NULL);
if (rsa == NULL) {
err = ERR_get_error();
printf("Error = %s\n",ERR_reason_error_string(err));
return NULL;
}
pkey = EVP_PKEY_new();
EVP_PKEY_assign_RSA(pkey, rsa);
return pkey;
}
...
myPrivateKey := rsa.GenerateKey(rand.Reader, 1024);
...
public static KeyPair getRSAKey() throws NoSuchAlgorithmException {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(512);
KeyPair key = keyGen.generateKeyPair();
return key;
}
...
crmfObject = crypto.generateCRMFRequest(
"CN=" + name.value,
password.value,
authenticator,
keyTransportCert,
"setCRMFRequest();",
512, null, "rsa-dual-use");
...
...
CCCrypt(kCCEncrypt,
kCCAlgorithmDES,
kCCOptionPKCS7Padding,
key,
kCCKeySizeDES, // 64-bit key size
iv,
plaintext,
sizeof(plaintext),
ciphertext,
sizeof(ciphertext),
&numBytesEncrypted);
...
...
$keysize = 1024;
$options = array('private_key_bits' => $keysize, 'private_key_type' => OPENSSL_KEYTYPE_RSA);
$res = openssl_pkey_new($options);
...
...
from Crypto.PublicKey import RSA
key = RSA.generate(1024)
...
require 'openssl'
...
pkey = OpenSSL::PKey::RSA.new 1024
...
...
let iv = getTrueRandomIV()
...
let cStatus = CCCrypt(UInt32(kCCEncrypt),
UInt32(kCCAlgorithmDES),
UInt32(kCCOptionPKCS7Padding),
key,
UInt32(kCCKeySizeDES), // 64-bit key size
iv,
plaintext,
plaintextLength,
ciphertext,
ciphertextLength,
&numBytesEncrypted)
...
EVP_DecryptUpdate
, lo que producirá un error al descifrar el texto cifrado.
...
EVP_DecryptInit_ex(&ctx, EVP_aes_256_gcm(), NULL, key, iv);
...
if(!EVP_DecryptFinal_ex(&ctx, outBuf+outBytes, &tmpOutBytes))
prtErrAndExit(1, "ERROR: EVP_DecryptFinal_ex did not work...\n");
...
KeyGenerator
, lo que posiblemente producirá el uso de una clave de un tamaño menor que el recomendado:
...
final String CIPHER_INPUT = "123456ABCDEFG";
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
SecretKey secretKey = keyGenerator.generateKey();
byte[] byteKey = secretKey.getEncoded();
....
OpenSSL::Cipher#update
, lo que da como resultado un error al descifrar el texto cifrado:
require 'openssl'
...
decipher = OpenSSL::Cipher::AES.new(128, :GCM)
decipher.decrypt
decipher.key = key
decipher.iv = iv
plain = decipher.final #missed update method
...
import (
"crypto/aes"
"crypto/cipher"
"os"
)
...
iv = b'1234567890123456'
CTRstream = cipher.NewCTR(block, iv)
CTRstream.XORKeyStream(plaintext, ciphertext)
...
f := os.Create("data.enc")
f.Write(ciphertext)
f.Close()
Example 1
, dado que iv
se establece como un vector de inicialización constante, este es susceptible a ataques de reutilización.
...
const cipher = crypto.createCipheriv("AES-256-CTR", key, 'iv')
const ciphertext = cipher.update(plaintext, 'utf8');
cipher.final();
fs.writeFile('my_encrypted_data', ciphertext, function (err) {
...
});
from Crypto.Cipher import AES
from Crypto import Random
...
key = Random.new().read(AES.block_size)
iv = b'1234567890123456'
cipher = AES.new(key, AES.MODE_CTR, iv, counter)
...
encrypted = cipher.encrypt(data)
f = open("data.enc", "wb")
f.write(encrypted)
f.close()
...
Example 1
, dado que iv
se establece como un vector de inicialización constante, este será susceptible a ataques de reutilización.
require 'openssl'
...
cipher = OpenSSL::Cipher.new('AES-256-CTR')
cipher.encrypt
cipher.iv='iv'
...
encrypted = cipher.update(data) + cipher.final
File.open('my_encrypted_data', 'w') do |file|
file.write(encrypted)
end
Example 1
, dado que OpenSSL::Cipher#iv=
se establece como un vector de inicialización constante, este será susceptible a ataques de reutilización.
...
RSACryptoServiceProvider rsa1 = new RSACryptoServiceProvider(Convert.ToInt32(tx.Text));
...
Example 1
se ejecutará correctamente, pero cualquier persona con acceso a esta funcionalidad podrá manipular el parámetro de tamaño de clave en el algoritmo de cifrado modificando el valor del cuadro de texto tx.Text
. Una vez lanzado el programa, puede resultar muy difícil deshacer un problema relacionado con tamaños de clave controlados por el usuario, dado que probablemente no habría forma de saber si un usuario malintencionado ha determinado el tamaño de clave de una operación de cifrado concreta.
...
rsa.GenerateKey(random, user_input)
...
Example 1
se ejecutará correctamente, pero cualquier persona con acceso a esta funcionalidad podrá manipular el parámetro de tamaño de clave para el algoritmo de cifrado, dado que el usuario puede controlar la variable user_input
. Tras un lanzamiento de software, puede resultar complicado deshacer un problema relacionado con los tamaños de clave controlados por el usuario. Es extremadamente difícil saber si un usuario malintencionado controló el tamaño de clave de una operación de cifrado determinada.
...
Properties prop = new Properties();
prop.load(new FileInputStream("config.properties"));
String keySize = prop.getProperty("keySize");
...
PBEKeySpec spec = new PBEKeySpec(
password.toCharArray(),
saltBytes,
pswdIterations,
Integer.parseInt(keySize)
);
SecretKey secretKey = factory.generateSecret(spec);
SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
...
Example 1
se ejecutará correctamente, pero cualquier persona con acceso a esta función podrá manipular el parámetro de tamaño de clave en el algoritmo de cifrado modificando la propiedad keySize
. Una vez lanzado el programa, puede resultar muy difícil deshacer un problema relacionado con tamaños de clave controlados por el usuario, dado que probablemente no habría forma de saber si un usuario malintencionado ha determinado el tamaño de clave de una operación de cifrado concreta.
...
@property (strong, nonatomic) IBOutlet UITextField *inputTextField;
...
CCCrypt(kCCEncrypt,
kCCAlgorithmAES,
kCCOptionPKCS7Padding,
key,
sizeof(_inputTextField.text),
iv,
plaintext,
sizeof(plaintext),
ciphertext,
sizeof(ciphertext),
&numBytesEncrypted);
...
Example 1
se ejecutará correctamente, pero cualquier persona con acceso a esta función podrá manipular el parámetro de tamaño de clave en el algoritmo de cifrado modificando el texto en el UITextField inputTextField
. Una vez lanzado el programa, puede resultar muy difícil deshacer un problema relacionado con tamaños de clave controlados por el usuario, dado que probablemente no habría forma de saber si un usuario malintencionado ha determinado el tamaño de clave de una operación de cifrado concreta.
...
$hash = hash_pbkdf2('sha256', $password, $random_salt, 100000, strlen($password));
...
Example 1
se ejecutará correctamente, pero cualquier persona con acceso a esta función podrá manipular el parámetro de tamaño de clave para el algoritmo de cifrado dado que la variable user_input
puede ser controlada por el usuario. Una vez lanzado el programa, puede resultar muy difícil deshacer un problema relacionado con tamaños de clave controlados por el usuario, dado que probablemente no habría forma de saber si un usuario malintencionado ha determinado el tamaño de clave de una operación de cifrado concreta.
...
dk = hashlib.pbkdf2_hmac('sha256', password, random_salt, 100000, dklen=user_input)
...
Example 1
se ejecutará correctamente, pero cualquier persona con acceso a esta función podrá manipular el parámetro de tamaño de clave para el algoritmo de cifrado dado que la variable user_input
puede ser controlada por el usuario. Una vez lanzado el programa, puede resultar muy difícil deshacer un problema relacionado con tamaños de clave controlados por el usuario, dado que probablemente no habría forma de saber si un usuario malintencionado ha determinado el tamaño de clave de una operación de cifrado concreta.
...
dk = OpenSSL::PKCS5.pbkdf2_hmac(password, random_salt, 100000, user_input, digest)
...
Example 1
se ejecutará correctamente, pero cualquier persona con acceso a esta función podrá manipular el parámetro de tamaño de clave para el algoritmo de cifrado dado que la variable user_input
puede ser controlada por el usuario. Una vez lanzado el programa, puede resultar muy difícil deshacer un problema relacionado con tamaños de clave controlados por el usuario, dado que probablemente no habría forma de saber si un usuario malintencionado ha determinado el tamaño de clave de una operación de cifrado concreta.
...
@IBOutlet weak var inputTextField : UITextField!
...
let key = (inputTextField.text as NSString).dataUsingEncoding(NSUTF8StringEncoding)
let keyPointer = UnsafePointer<UInt8>(key.bytes)
let keyLength = size_t(key.length)
...
let operation : CCOperation = UInt32(kCCEncrypt)
let algoritm : CCAlgorithm = UInt32(kCCAlgorithmAES128)
let options : CCOptions = UInt32(kCCOptionPKCS7Padding)
var numBytesEncrypted :size_t = 0
CCCrypt(operation,
algorithm,
options,
keyPointer,
keyLength,
iv,
plaintextPointer,
plaintextLength,
ciphertextPointer,
ciphertextLength,
&numBytesEncrypted)
...
Example 1
se ejecutará correctamente, pero cualquier persona con acceso a esta función podrá manipular el parámetro de tamaño de clave en el algoritmo de cifrado modificando el texto en el UITextField inputTextField
. Una vez lanzado el programa, puede resultar muy difícil deshacer un problema relacionado con tamaños de clave controlados por el usuario, dado que probablemente no habría forma de saber si un usuario malintencionado ha determinado el tamaño de clave de una operación de cifrado concreta.doSecurityCheck()
realiza una comprobación de seguridad y se puede reemplazar con una clase secundaria.
public class BadSecurityCheck {
private int id;
public BadSecurityCheck() {
doSecurityCheck();
id = 1;
}
protected void doSecurityCheck() {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new SomePermission("SomeAction"));
}
}
}
SecurityManager
no está autorizado, se lanzará una excepción SecurityException
, que es una excepción de tiempo de ejecución y detendrá la ejecución del programa. Como BadSecurityCheck
no es final
y el método doSecurityCheck()
está protected
y no es final
, significa que esta clase se puede dividir en subclases para anular esta función. doSecurityCheck()
queda anulado por una subclase:
public class EvilSubclass extends BadSecurityCheck {
private int id;
public EvilSubclass() {
super();
}
protected void doSecurityCheck() {
//do nothing
}
}
EvilSubclass
, el constructor primero llama a super()
, para invocar al constructor de la súperclase. Este a su vez llama a la función doSecurityCheck()
, pero Java buscará primero la función en la subclase antes de buscar en la superclase, por tanto invocando el método controlado por el usuario malintencionado que elude la comprobación de seguridad, por lo que id
se establecerá en 1
.
<sp:TransportBinding>
<wsp:Policy>
<sp:TransportToken>
<wsp:Policy>
<sp:HttpToken/>
</wsp:Policy>
</sp:TransportToken>
...
</sp:TransportBinding>