class OpenSSL::Cipher
Bietet symmetrische Algorithmen für Verschlüsselung und Entschlüsselung. Die verfügbaren Algorithmen hängen von der jeweiligen Version von OpenSSL ab, die installiert ist.
Auflistung aller unterstützten Algorithmen
Eine Liste der unterstützten Algorithmen kann durch
puts OpenSSL::Cipher.ciphers
Instanziieren eines Cipher
erhalten werden. Es gibt mehrere Möglichkeiten, eine Cipher-Instanz zu erstellen. Im Allgemeinen wird ein Cipher-Algorithmus anhand seines Namens, der Schlüssellänge in Bits und des zu verwendenden Chiffriermodus kategorisiert. Der generischste Weg, ein Cipher zu erstellen, ist der folgende:
cipher = OpenSSL::Cipher.new('<name>-<key length>-<mode>')
Das heißt, ein String, der aus der mit Bindestrichen verbundenen Verkettung der einzelnen Komponenten Name, Schlüssellänge und Modus besteht. Entweder vollständig großgeschriebene oder vollständig kleingeschriebene Strings können verwendet werden, zum Beispiel:
cipher = OpenSSL::Cipher.new('aes-128-cbc')
Auswahl des Verschlüsselungs- oder Entschlüsselungsmodus
Verschlüsselung und Entschlüsselung sind bei symmetrischen Algorithmen oft sehr ähnliche Operationen. Dies spiegelt sich darin wider, dass keine unterschiedlichen Klassen für die jeweilige Operation gewählt werden müssen; beides kann mit derselben Klasse durchgeführt werden. Dennoch müssen wir nach dem Erhalt einer Cipher-Instanz der Instanz mitteilen, was wir damit vorhaben. Wir müssen also entweder
cipher.encrypt
oder
cipher.decrypt
auf der Cipher-Instanz aufrufen. Dies sollte der erste Aufruf nach der Erstellung der Instanz sein, da andernfalls bereits gesetzte Konfigurationen im Prozess verloren gehen könnten.
Auswahl eines Schlüssels
Die symmetrische Verschlüsselung erfordert einen Schlüssel, der für die verschlüsselnde und die entschlüsselnde Partei derselbe ist und nach der anfänglichen Schlüsselvereinbarung als private Information geheim gehalten werden sollte. Es gibt viele Möglichkeiten, unsichere Schlüssel zu erstellen, die bemerkenswerteste ist, einfach ein Passwort als Schlüssel zu nehmen, ohne das Passwort weiter zu verarbeiten. Ein einfacher und sicherer Weg, einen Schlüssel für ein bestimmtes Cipher zu erstellen, ist:
cipher = OpenSSL::Cipher.new('aes-256-cfb') cipher.encrypt key = cipher.random_key # also sets the generated key on the Cipher
Wenn Sie unbedingt Passwörter als Verschlüsselungsschlüssel verwenden müssen, sollten Sie Password-Based Key Derivation Function 2 (PBKDF2) verwenden, indem Sie den Schlüssel mit Hilfe der von OpenSSL::PKCS5.pbkdf2_hmac_sha1 oder OpenSSL::PKCS5.pbkdf2_hmac bereitgestellten Funktionalität generieren.
Obwohl es Cipher#pkcs5_keyivgen gibt, ist dessen Verwendung veraltet und sollte nur in Legacy-Anwendungen verwendet werden, da es nicht die neueren PKCS#5 v2 Algorithmen verwendet.
Auswahl eines IV
Die Chiffriermodi CBC, CFB, OFB und CTR benötigen alle einen „Initialisierungsvektor“, kurz IV. Der ECB-Modus ist der einzige Modus, der keinen IV benötigt, aber es gibt fast keinen legitimen Anwendungsfall für diesen Modus, da er Muster im Klartext nicht ausreichend verbirgt. Daher:
Sie sollten niemals den ECB-Modus verwenden, es sei denn, Sie sind absolut sicher, dass Sie ihn unbedingt benötigen.
Aus diesem Grund werden Sie in jedem Fall mit einem Modus enden, der explizit einen IV erfordert. Obwohl der IV als öffentliche Information betrachtet werden kann, d. h. er kann einmal generiert öffentlich übertragen werden, sollte er dennoch unvorhersehbar bleiben, um bestimmte Arten von Angriffen zu verhindern. Daher idealerweise:
Erstellen Sie für jede Verschlüsselung Ihres Chiffres immer einen sicheren zufälligen IV.
Für jede Datenverschlüsselung sollte ein neuer, zufälliger IV erstellt werden. Betrachten Sie den IV als eine Nonce (einmal verwendete Nummer) – er ist öffentlich, aber zufällig und unvorhersehbar. Ein sicherer zufälliger IV kann wie folgt erstellt werden:
cipher = ... cipher.encrypt key = cipher.random_key iv = cipher.random_iv # also sets the generated IV on the Cipher
Obwohl der Schlüssel im Allgemeinen ebenfalls ein zufälliger Wert ist, ist er eine schlechte Wahl als IV. Es gibt ausgeklügelte Wege, wie ein Angreifer einen solchen IV ausnutzen kann. Als Faustregel gilt, dass die Offenlegung des Schlüssels direkt oder indirekt unter allen Umständen vermieden werden sollte und Ausnahmen nur aus gutem Grund gemacht werden sollten.
Aufrufen von Cipher#final
ECB (das nicht verwendet werden sollte) und CBC sind beides blockbasierte Modi. Das bedeutet, dass sie im Gegensatz zu anderen Streaming-basierten Modi auf Datenblöcken fester Größe operieren und daher einen „Finalisierungsschritt“ erfordern, um den letzten Datenblock durch entsprechende Behandlung einer Form von Padding zu erzeugen oder korrekt zu entschlüsseln. Daher ist es unerlässlich, die Ausgabe von OpenSSL::Cipher#final zu Ihrem Verschlüsselungs-/Entschlüsselungsbuffer hinzuzufügen, sonst erhalten Sie Entschlüsselungsfehler oder abgeschnittene Daten.
Obwohl dies für Streaming-Modus-Chiffren nicht wirklich notwendig ist, wird dennoch empfohlen, dasselbe Muster zu verwenden, indem die Ausgabe von Cipher#final ebenfalls hinzugefügt wird – dies ermöglicht Ihnen auch, zukünftig einfacher zwischen Modi zu wechseln.
Einige Daten verschlüsseln und entschlüsseln
data = "Very, very confidential data" cipher = OpenSSL::Cipher.new('aes-128-cbc') cipher.encrypt key = cipher.random_key iv = cipher.random_iv encrypted = cipher.update(data) + cipher.final ... decipher = OpenSSL::Cipher.new('aes-128-cbc') decipher.decrypt decipher.key = key decipher.iv = iv plain = decipher.update(encrypted) + decipher.final puts data == plain #=> true
Authentifizierte Verschlüsselung und zugehörige Daten (AEAD)
Wenn die verwendete OpenSSL-Version dies unterstützt, sollte ein authentifizierter Verschlüsselungsmodus (wie GCM oder CCM) immer einem nicht authentifizierten Modus vorgezogen werden. Derzeit unterstützt OpenSSL AE nur in Kombination mit zugehörigen Daten (AEAD), bei denen zusätzliche zugehörige Daten in den Verschlüsselungsprozess einbezogen werden, um am Ende der Verschlüsselung einen Tag zu berechnen. Dieser Tag wird auch im Entschlüsselungsprozess verwendet und durch die Überprüfung seiner Gültigkeit wird die Authentizität eines gegebenen Chiffretexts hergestellt.
Dies ist den nicht authentifizierten Modi überlegen, da es erkennt, ob jemand tatsächlich den Chiffretext nach seiner Verschlüsselung verändert hat. Dies verhindert bösartige Modifikationen des Chiffretexts, die ansonsten ausgenutzt werden könnten, um Chiffretexte auf eine Weise zu verändern, die potenziellen Angreifern zugutekommt.
Zugehörige Daten, auch zusätzliche authentifizierte Daten (AAD) genannt, werden optional verwendet, wenn zusätzliche Informationen, wie z. B. Header oder Metadaten, vorhanden sind, die ebenfalls authentifiziert werden müssen, aber nicht unbedingt verschlüsselt werden müssen.
Ein Beispiel mit GCM (Galois/Counter Mode). Sie haben einen 16-Byte-Schlüssel, ein 12-Byte (96 Bit) Nonce und die zugehörigen Daten auth_data. Achten Sie darauf, das Paar aus Schlüssel und Nonce nicht wiederzuverwenden. Die Wiederverwendung einer Nonce ruiniert die Sicherheitsgarantien des GCM-Modus.
key = OpenSSL::Random.random_bytes(16) nonce = OpenSSL::Random.random_bytes(12) auth_data = "authenticated but unencrypted data" data = "encrypted data" cipher = OpenSSL::Cipher.new('aes-128-gcm').encrypt cipher.key = key cipher.iv = nonce cipher.auth_data = auth_data encrypted = cipher.update(data) + cipher.final tag = cipher.auth_tag(16)
Nun sind Sie der Empfänger. Sie kennen den Schlüssel und haben Nonce, auth_data, verschlüsselt und tag über ein nicht vertrauenswürdiges Netzwerk erhalten. Beachten Sie, dass GCM einen Tag beliebiger Länge zwischen 1 und 16 Bytes akzeptiert. Möglicherweise müssen Sie zusätzlich prüfen, ob der empfangene Tag die richtige Länge hat, oder Sie erlauben Angreifern, einen gültigen einstellig-langen Tag für den manipulierten Chiffretext mit einer Wahrscheinlichkeit von 1/256 zu fälschen.
raise "tag is truncated!" unless tag.bytesize == 16 decipher = OpenSSL::Cipher.new('aes-128-gcm').decrypt decipher.key = key decipher.iv = nonce decipher.auth_tag = tag # could be called at any time before #final decipher.auth_data = auth_data decrypted = decipher.update(encrypted) + decipher.final puts data == decrypted #=> true
Beachten Sie, dass andere AEAD-Chiffren zusätzliche Schritte erfordern können, wie z. B. die Festlegung der erwarteten Tag-Länge (auth_tag_len=) oder der Gesamtdatenlänge (ccm_data_len=) im Voraus. Lesen Sie die entsprechende Manpage für Details.
Öffentliche Klassenmethoden
Source
static VALUE
ossl_s_ciphers(VALUE self)
{
VALUE ary;
ary = rb_ary_new();
OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_CIPHER_METH,
add_cipher_name_to_ary,
(void*)ary);
return ary;
}
Gibt die Namen aller verfügbaren Chiffren als Array zurück.
Source
static VALUE
ossl_cipher_initialize(VALUE self, VALUE str)
{
EVP_CIPHER_CTX *ctx;
const EVP_CIPHER *cipher;
VALUE cipher_holder;
GetCipherInit(self, ctx);
if (ctx) {
ossl_raise(rb_eRuntimeError, "Cipher already initialized!");
}
cipher = ossl_evp_cipher_fetch(str, &cipher_holder);
AllocCipher(self, ctx);
if (EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, -1) != 1)
ossl_raise(eCipherError, "EVP_CipherInit_ex");
rb_ivar_set(self, id_cipher_holder, cipher_holder);
return self;
}
Der String muss einen gültigen Chiffrenamen enthalten, z. B. „aes-256-cbc“.
Eine Liste der Chiffrenamen ist durch Aufruf von OpenSSL::Cipher.ciphers verfügbar.
Öffentliche Instanzmethoden
Source
static VALUE
ossl_cipher_set_auth_data(VALUE self, VALUE data)
{
EVP_CIPHER_CTX *ctx;
unsigned char *in;
long in_len, out_len;
StringValue(data);
in = (unsigned char *) RSTRING_PTR(data);
in_len = RSTRING_LEN(data);
GetCipher(self, ctx);
if (!(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER))
ossl_raise(eCipherError, "AEAD not supported by this cipher");
if (!ossl_cipher_update_long(ctx, NULL, &out_len, in, in_len))
ossl_raise(eCipherError, "couldn't set additional authenticated data");
return data;
}
Legt zusätzliche authentifizierte Daten (AAD), auch zugehörige Daten genannt, für dieses Cipher fest. Diese Methode ist für AEAD-Chiffren verfügbar.
Der Inhalt dieses Feldes sollten nicht sensible Daten sein, die zum Chiffretext hinzugefügt werden, um den Authentifizierungstag zu generieren, der den Inhalt des Chiffretexts validiert.
Diese Methode muss nach dem Setzen von key= und iv= aufgerufen werden, aber bevor die eigentliche Verschlüsselung oder Entschlüsselung mit update gestartet wird. In einigen Chiffriermodi müssen möglicherweise auch auth_tag_len= und ccm_data_len= vor dieser Methode aufgerufen werden.
Siehe auch den Abschnitt „AEAD Interface“ der Manpage EVP_EncryptInit(3). Diese Methode ruft intern EVP_CipherUpdate() mit dem Ausgabe-Buffer auf NULL gesetzt auf.
Source
static VALUE
ossl_cipher_get_auth_tag(int argc, VALUE *argv, VALUE self)
{
VALUE vtag_len, ret;
EVP_CIPHER_CTX *ctx;
int tag_len = 16;
rb_scan_args(argc, argv, "01", &vtag_len);
if (NIL_P(vtag_len))
vtag_len = rb_attr_get(self, id_auth_tag_len);
if (!NIL_P(vtag_len))
tag_len = NUM2INT(vtag_len);
GetCipher(self, ctx);
if (!(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER))
ossl_raise(eCipherError, "authentication tag not supported by this cipher");
ret = rb_str_new(NULL, tag_len);
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, tag_len, RSTRING_PTR(ret)))
ossl_raise(eCipherError, "retrieving the authentication tag failed");
return ret;
}
Holt den generierten Authentifizierungstag. Diese Methode ist für AEAD-Chiffren verfügbar und sollte nach Abschluss der Verschlüsselung durch Aufruf von final aufgerufen werden.
Der zurückgegebene Tag ist tag_len Bytes lang. Einige Chiffriermodi erfordern die gewünschte Länge im Voraus durch einen separaten Aufruf von auth_tag_len=, bevor die Verschlüsselung gestartet wird.
Siehe auch den Abschnitt „AEAD Interface“ der Manpage EVP_EncryptInit(3). Diese Methode ruft intern EVP_CIPHER_CTX_ctrl() mit EVP_CTRL_AEAD_GET_TAG auf.
Source
static VALUE
ossl_cipher_set_auth_tag(VALUE self, VALUE vtag)
{
EVP_CIPHER_CTX *ctx;
unsigned char *tag;
int tag_len;
StringValue(vtag);
tag = (unsigned char *) RSTRING_PTR(vtag);
tag_len = RSTRING_LENINT(vtag);
GetCipher(self, ctx);
if (!(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER))
ossl_raise(eCipherError, "authentication tag not supported by this cipher");
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, tag_len, tag))
ossl_raise(eCipherError, "unable to set AEAD tag");
return vtag;
}
Legt den Authentifizierungstag fest, um die Integrität des Chiffretexts zu überprüfen.
Der Authentifizierungstag muss vor dem Aufruf von final gesetzt werden. Der Tag wird während des Aufrufs von final überprüft.
Beachten Sie, dass für CCM- und OCB-Modi die erwartete Länge des Tags vor Beginn der Entschlüsselung durch einen separaten Aufruf von auth_tag_len= gesetzt werden muss. Der Inhalt des Tags kann jederzeit vor dem Aufruf von final angegeben werden.
HINWEIS: Der Aufrufer muss sicherstellen, dass der an diese Methode übergebene String die gewünschte Länge hat. Einige Chiffriermodi unterstützen variable Tag-Längen, und diese Methode kann einen gekürzten Tag akzeptieren, ohne eine Ausnahme auszulösen.
Siehe auch den Abschnitt „AEAD Interface“ der Manpage EVP_EncryptInit(3). Diese Methode ruft intern EVP_CIPHER_CTX_ctrl() mit EVP_CTRL_AEAD_SET_TAG auf.
Source
static VALUE
ossl_cipher_set_auth_tag_len(VALUE self, VALUE vlen)
{
int tag_len = NUM2INT(vlen);
EVP_CIPHER_CTX *ctx;
GetCipher(self, ctx);
if (!(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER))
ossl_raise(eCipherError, "AEAD not supported by this cipher");
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, tag_len, NULL))
ossl_raise(eCipherError, "unable to set authentication tag length");
/* for #auth_tag */
rb_ivar_set(self, id_auth_tag_len, INT2NUM(tag_len));
return vlen;
}
Legt die Länge des erwarteten Authentifizierungstags für dieses Cipher fest. Diese Methode ist für einige AEAD-Chiffren verfügbar, die die Festlegung der Länge vor Beginn der Verschlüsselung oder Entschlüsselung erfordern, wie z. B. CCM-Modus oder OCB-Modus.
Für CCM- und OCB-Modus muss die Tag-Länge vor dem Setzen von iv= gesetzt werden.
Siehe auch den Abschnitt „AEAD Interface“ der Manpage EVP_EncryptInit(3). Diese Methode ruft intern EVP_CIPHER_CTX_ctrl() mit EVP_CTRL_AEAD_SET_TAG und einem NULL-Buffer auf.
Source
static VALUE
ossl_cipher_is_authenticated(VALUE self)
{
EVP_CIPHER_CTX *ctx;
GetCipher(self, ctx);
return (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER) ? Qtrue : Qfalse;
}
Gibt an, ob diese Cipher-Instanz einen AEAD-Modus verwendet.
Source
static VALUE
ossl_cipher_block_size(VALUE self)
{
EVP_CIPHER_CTX *ctx;
GetCipher(self, ctx);
return INT2NUM(EVP_CIPHER_CTX_block_size(ctx));
}
Gibt die Blockgröße in Bytes zurück, auf denen dieses Cipher operiert.
Source
static VALUE
ossl_cipher_set_ccm_data_len(VALUE self, VALUE data_len)
{
int in_len, out_len;
EVP_CIPHER_CTX *ctx;
in_len = NUM2INT(data_len);
GetCipher(self, ctx);
if (EVP_CipherUpdate(ctx, NULL, &out_len, NULL, in_len) != 1)
ossl_raise(eCipherError, NULL);
return data_len;
}
Legt die Gesamtlänge der Klartext-/Chiffretextnachricht fest, die von update im CCM-Modus verarbeitet wird.
Stellen Sie sicher, dass Sie diese Methode aufrufen, nachdem key= und iv= gesetzt wurden, und bevor auth_data= oder update aufgerufen werden.
Diese Methode ist nur für CCM-Modus-Chiffren verfügbar.
Siehe auch den Abschnitt „AEAD Interface“ der Manpage EVP_EncryptInit(3).
Source
static VALUE
ossl_cipher_decrypt(VALUE self)
{
return ossl_cipher_init(self, 0);
}
Source
static VALUE
ossl_cipher_encrypt(VALUE self)
{
return ossl_cipher_init(self, 1);
}
Source
static VALUE
ossl_cipher_final(VALUE self)
{
EVP_CIPHER_CTX *ctx;
int out_len;
VALUE str;
GetCipher(self, ctx);
str = rb_str_new(0, EVP_CIPHER_CTX_block_size(ctx));
if (!EVP_CipherFinal_ex(ctx, (unsigned char *)RSTRING_PTR(str), &out_len)) {
/* For AEAD ciphers, this is likely an authentication failure */
if (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER) {
/* For AEAD ciphers, EVP_CipherFinal_ex failures are authentication tag verification failures */
ossl_raise(eAuthTagError, "AEAD authentication tag verification failed");
}
else {
/* For non-AEAD ciphers */
ossl_raise(eCipherError, "cipher final failed");
}
}
assert(out_len <= RSTRING_LEN(str));
rb_str_set_len(str, out_len);
return str;
}
Gibt die verbleibenden Daten im Cipher-Objekt zurück. Weitere Aufrufe von Cipher#update oder Cipher#final sind ungültig. Dieser Aufruf sollte immer als letzter Aufruf einer Verschlüsselungs- oder Entschlüsselungsoperation erfolgen, nachdem der gesamte Klartext oder Chiffretext an die Cipher-Instanz übergeben wurde.
Bei der Verschlüsselung mit einem AEAD-Chiffre kann der Authentifizierungstag nach dem Aufruf von final mit auth_tag abgerufen werden.
Bei der Entschlüsselung mit einem AEAD-Chiffre verifiziert diese Methode die Integrität des Chiffretexts und der zugehörigen Daten anhand des Authentifizierungstags, der vor dem Aufruf dieser Methode durch auth_tag= gesetzt werden muss. Wenn die Verifizierung fehlschlägt, wird eine CipherError ausgelöst.
Source
static VALUE
ossl_cipher_set_iv(VALUE self, VALUE iv)
{
EVP_CIPHER_CTX *ctx;
int iv_len = 0;
StringValue(iv);
GetCipher(self, ctx);
if (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER)
iv_len = (int)(VALUE)EVP_CIPHER_CTX_get_app_data(ctx);
if (!iv_len)
iv_len = EVP_CIPHER_CTX_iv_length(ctx);
if (RSTRING_LEN(iv) != iv_len)
ossl_raise(rb_eArgError, "iv must be %d bytes", iv_len);
if (EVP_CipherInit_ex(ctx, NULL, NULL, NULL, (unsigned char *)RSTRING_PTR(iv), -1) != 1)
ossl_raise(eCipherError, NULL);
return iv;
}
Legt den Chiffre-IV fest. Bitte beachten Sie, dass, da Sie niemals den ECB-Modus verwenden sollten, ein IV immer explizit erforderlich ist und vor der Verschlüsselung gesetzt werden sollte. Der IV selbst kann sicher öffentlich übertragen werden.
Diese Methode erwartet, dass der String die Länge hat, die gleich iv_len ist. Um mit einem AEAD-Chiffre eine andere IV-Länge zu verwenden, muss iv_len= vor dem Aufruf dieser Methode gesetzt werden.
HINWEIS: In den Konventionen der OpenSSL-API kann der IV-Wert in einigen Chiffriermodi dem „Nonce“ entsprechen. Einzelheiten entnehmen Sie bitte den OpenSSL-Manpages.
Siehe auch die Manpage EVP_CipherInit_ex(3).
Source
static VALUE
ossl_cipher_iv_length(VALUE self)
{
EVP_CIPHER_CTX *ctx;
int len = 0;
GetCipher(self, ctx);
if (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER)
len = (int)(VALUE)EVP_CIPHER_CTX_get_app_data(ctx);
if (!len)
len = EVP_CIPHER_CTX_iv_length(ctx);
return INT2NUM(len);
}
Gibt die erwartete Länge eines IV für dieses Cipher in Bytes zurück.
Source
static VALUE
ossl_cipher_set_iv_length(VALUE self, VALUE iv_length)
{
int len = NUM2INT(iv_length);
EVP_CIPHER_CTX *ctx;
GetCipher(self, ctx);
if (!(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER))
ossl_raise(eCipherError, "cipher does not support AEAD");
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, len, NULL))
ossl_raise(eCipherError, "unable to set IV length");
/*
* EVP_CIPHER_CTX_iv_length() returns the default length. So we need to save
* the length somewhere. Luckily currently we aren't using app_data.
*/
EVP_CIPHER_CTX_set_app_data(ctx, (void *)(VALUE)len);
return iv_length;
}
Legt die IV/Nonce-Länge für dieses Cipher fest. Diese Methode ist für AEAD-Chiffren verfügbar, die variable IV-Längen unterstützen. Diese Methode kann aufgerufen werden, wenn eine andere IV-Länge als die Standardeinstellung von OpenSSL gewünscht wird, bevor iv= aufgerufen wird.
Siehe auch den Abschnitt „AEAD Interface“ der Manpage EVP_EncryptInit(3). Diese Methode ruft intern EVP_CIPHER_CTX_ctrl() mit EVP_CTRL_AEAD_SET_IVLEN auf.
Source
static VALUE
ossl_cipher_set_key(VALUE self, VALUE key)
{
EVP_CIPHER_CTX *ctx;
int key_len;
StringValue(key);
GetCipher(self, ctx);
key_len = EVP_CIPHER_CTX_key_length(ctx);
if (RSTRING_LEN(key) != key_len)
ossl_raise(rb_eArgError, "key must be %d bytes", key_len);
if (EVP_CipherInit_ex(ctx, NULL, NULL, (unsigned char *)RSTRING_PTR(key), NULL, -1) != 1)
ossl_raise(eCipherError, NULL);
rb_ivar_set(self, id_key_set, Qtrue);
return key;
}
Legt den Chiffrierschlüssel fest. Um einen Schlüssel zu generieren, sollten Sie entweder eine sichere zufällige Byte-Zeichenkette verwenden oder, wenn der Schlüssel aus einem Passwort abgeleitet werden soll, sollten Sie sich auf die von OpenSSL::PKCS5 bereitgestellte PBKDF2-Funktionalität verlassen. Um einen Schlüssel basierend auf sicheren Zufallswerten zu generieren, kann Cipher#random_key verwendet werden.
Rufen Sie diese Methode nur auf, nachdem Sie Cipher#encrypt oder Cipher#decrypt aufgerufen haben.
Siehe auch die Manpage EVP_CipherInit_ex(3).
Source
static VALUE
ossl_cipher_key_length(VALUE self)
{
EVP_CIPHER_CTX *ctx;
GetCipher(self, ctx);
return INT2NUM(EVP_CIPHER_CTX_key_length(ctx));
}
Gibt die Schlüssellänge des Cipher in Bytes zurück.
Source
static VALUE
ossl_cipher_set_key_length(VALUE self, VALUE key_length)
{
int len = NUM2INT(key_length);
EVP_CIPHER_CTX *ctx;
GetCipher(self, ctx);
if (EVP_CIPHER_CTX_set_key_length(ctx, len) != 1)
ossl_raise(eCipherError, NULL);
return key_length;
}
Legt die Schlüssellänge des Chiffres fest. Wenn das Chiffre eine feste Länge hat, ist der Versuch, die Schlüssellänge auf einen anderen Wert als den festen Wert zu setzen, ein Fehler.
Unter normalen Umständen müssen Sie diese Methode nicht aufrufen (und sollten es wahrscheinlich auch nicht).
Weitere Informationen finden Sie unter EVP_CIPHER_CTX_set_key_length.
Source
static VALUE
ossl_cipher_name(VALUE self)
{
EVP_CIPHER_CTX *ctx;
GetCipher(self, ctx);
return rb_str_new2(EVP_CIPHER_name(EVP_CIPHER_CTX_cipher(ctx)));
}
Gibt den Kurznamen des Chiffres zurück, der leicht vom ursprünglichen Namen abweichen kann.
Source
static VALUE
ossl_cipher_set_padding(VALUE self, VALUE padding)
{
EVP_CIPHER_CTX *ctx;
int pad = NUM2INT(padding);
GetCipher(self, ctx);
if (EVP_CIPHER_CTX_set_padding(ctx, pad) != 1)
ossl_raise(eCipherError, NULL);
return padding;
}
Aktiviert oder deaktiviert Padding. Standardmäßig werden Verschlüsselungsoperationen mit Standard-Block-Padding aufgefüllt, und das Padding wird beim Entschlüsseln überprüft und entfernt. Wenn der Padding-Parameter Null ist, erfolgt keine Auffüllung; die Gesamtmenge der verschlüsselten oder entschlüsselten Daten muss ein Vielfaches der Blockgröße sein, andernfalls tritt ein Fehler auf.
Weitere Informationen finden Sie unter EVP_CIPHER_CTX_set_padding.
Source
static VALUE
ossl_cipher_pkcs5_keyivgen(int argc, VALUE *argv, VALUE self)
{
EVP_CIPHER_CTX *ctx;
const EVP_MD *digest;
VALUE vpass, vsalt, viter, vdigest, md_holder;
unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH], *salt = NULL;
int iter;
rb_scan_args(argc, argv, "13", &vpass, &vsalt, &viter, &vdigest);
StringValue(vpass);
if(!NIL_P(vsalt)){
StringValue(vsalt);
if(RSTRING_LEN(vsalt) != PKCS5_SALT_LEN)
ossl_raise(eCipherError, "salt must be an 8-octet string");
salt = (unsigned char *)RSTRING_PTR(vsalt);
}
iter = NIL_P(viter) ? 2048 : NUM2INT(viter);
if (iter <= 0)
rb_raise(rb_eArgError, "iterations must be a positive integer");
digest = NIL_P(vdigest) ? EVP_md5() : ossl_evp_md_fetch(vdigest, &md_holder);
GetCipher(self, ctx);
EVP_BytesToKey(EVP_CIPHER_CTX_cipher(ctx), digest, salt,
(unsigned char *)RSTRING_PTR(vpass), RSTRING_LENINT(vpass), iter, key, iv);
if (EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, -1) != 1)
ossl_raise(eCipherError, NULL);
OPENSSL_cleanse(key, sizeof key);
OPENSSL_cleanse(iv, sizeof iv);
rb_ivar_set(self, id_key_set, Qtrue);
return Qnil;
}
Generiert und setzt den Schlüssel/IV basierend auf einem Passwort.
WARNUNG: Diese Methode ist veraltet und sollte nicht verwendet werden. Diese Methode entspricht EVP_BytesToKey(), einer nicht standardmäßigen OpenSSL-Erweiterung der Legacy-PKCS #5 v1.5 Key Derivation Function. Siehe OpenSSL::KDF für andere Optionen zur Ableitung von Schlüsseln aus Passwörtern.
Parameter
-
salt muss ein 8-Byte-String sein, wenn er angegeben wird.
-
iterations ist eine Ganzzahl mit einem Standardwert von 2048.
-
digest ist ein
Digest-Objekt, das standardmäßig auf „MD5“ gesetzt ist.
Source
# File ext/openssl/lib/openssl/cipher.rb, line 55 def random_iv str = OpenSSL::Random.random_bytes(self.iv_len) self.iv = str end
Generiert einen zufälligen IV mit OpenSSL::Random.random_bytes, setzt ihn auf das Chiffre und gibt ihn zurück.
Sie müssen encrypt oder decrypt aufrufen, bevor Sie diese Methode aufrufen.
Source
# File ext/openssl/lib/openssl/cipher.rb, line 43 def random_key str = OpenSSL::Random.random_bytes(self.key_len) self.key = str end
Generiert einen zufälligen Schlüssel mit OpenSSL::Random.random_bytes, setzt ihn auf das Chiffre und gibt ihn zurück.
Sie müssen encrypt oder decrypt aufrufen, bevor Sie diese Methode aufrufen.
Source
static VALUE
ossl_cipher_reset(VALUE self)
{
EVP_CIPHER_CTX *ctx;
GetCipher(self, ctx);
if (EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, -1) != 1)
ossl_raise(eCipherError, NULL);
return self;
}
Source
static VALUE
ossl_cipher_update(int argc, VALUE *argv, VALUE self)
{
EVP_CIPHER_CTX *ctx;
unsigned char *in;
long in_len, out_len;
VALUE data, str;
rb_scan_args(argc, argv, "11", &data, &str);
if (!RTEST(rb_attr_get(self, id_key_set)))
ossl_raise(eCipherError, "key not set");
StringValue(data);
in = (unsigned char *)RSTRING_PTR(data);
in_len = RSTRING_LEN(data);
GetCipher(self, ctx);
/*
* As of OpenSSL 3.2, there is no reliable way to determine the required
* output buffer size for arbitrary cipher modes.
* https://github.com/openssl/openssl/issues/22628
*
* in_len+block_size is usually sufficient, but AES key wrap with padding
* ciphers require in_len+15 even though they have a block size of 8 bytes.
*
* Using EVP_MAX_BLOCK_LENGTH (32) as a safe upper bound for ciphers
* currently implemented in OpenSSL, but this can change in the future.
*/
if (in_len > LONG_MAX - EVP_MAX_BLOCK_LENGTH) {
ossl_raise(rb_eRangeError,
"data too big to make output buffer: %ld bytes", in_len);
}
out_len = in_len + EVP_MAX_BLOCK_LENGTH;
if (NIL_P(str)) {
str = rb_str_new(0, out_len);
} else {
StringValue(str);
if ((long)rb_str_capacity(str) >= out_len)
rb_str_modify(str);
else
rb_str_modify_expand(str, out_len - RSTRING_LEN(str));
}
if (!ossl_cipher_update_long(ctx, (unsigned char *)RSTRING_PTR(str), &out_len, in, in_len))
ossl_raise(eCipherError, NULL);
assert(out_len <= RSTRING_LEN(str));
rb_str_set_len(str, out_len);
return str;
}
Verschlüsselt Daten im Streaming-Modus. Übergeben Sie aufeinanderfolgende Datenblöcke an die Methode update, um sie zu verschlüsseln. Gibt den verschlüsselten Daten-Chunk zurück. Wenn Sie fertig sind, sollte die Ausgabe von Cipher#final zusätzlich zum Ergebnis hinzugefügt werden.
Wenn buffer angegeben ist, wird das Verschlüsselungs-/Entschlüsselungsergebnis darin geschrieben. buffer wird automatisch in der Größe angepasst.
HINWEIS: Bei der Entschlüsselung mit einem AEAD-Chiffre wird die Integrität der Ausgabe erst beim Aufruf von final überprüft.