Şifrelemede kullanılan anahtarı gizlemek

@EkremDincel @aib. @dildeolupbiten Biri bana tam olarak ne yapacağımı veya ne yapabileceklerimi soyleyebilirmi sohbeti kaybettim :sweat_smile: yani tam olarak istediğim dosya içeriğinin sadece benim veritabanı uygulamamin okuyabileceği bir şey yapmak istiyorum diğer veritabanlarindaki gibi. Json dosyaları gibi girdiğin de sana direk verileri vermesin kişi isterse sifrelesin veritabanını veya sifrelemesin ama veriyi çıplak bir şekilde sunmasin bunu nasıl yaparım bu olaylardan hiç anlamiyorum

Aşağıdaki kodları fikir vermesi açısından sizlerle paylaşıyorum.

Dosya Adı: database.py

from sqlite3 import OperationalError
from sqlite3.dbapi2 import Connection


def encrypt(string: str, password: int):
    return "".join(
        chr(ord(item) + password + index)
        for index, item in enumerate(string)
    )


def decrypt(string: str, password: int):
    return "".join(
        chr(ord(item) - password - index)
        for index, item in enumerate(string)
    )


class Database(Connection):
    def __init__(self, database: str, password: int, columns: list):
        super().__init__(database)
        try:
            self.real_password = [
                *self.execute(
                    "SELECT PASSWORD FROM DATA"
                )
            ][0][0]
            self.password = password
        except OperationalError:
            self.password = password
            self.real_password = encrypt(str(password), self.password)
            self.execute(
                f"CREATE TABLE DATA(NO, PASSWORD, {', '.join(columns)})"
            )
            data = tuple(
                encrypt(str(i), password)
                for i in ("0", password, *[None for _ in columns])
            )
            self.execute(
                f"INSERT INTO DATA VALUES({', '.join('?' * (len(columns) + 2))})",
                data
            )
            self.commit()

    def add_data(self, **kwargs):
        if encrypt(str(self.password), self.password) == self.real_password:
            no = str(len([i for i in self.execute("SELECT * FROM DATA")]))
            data = tuple(
                encrypt(i, self.password)
                for i in (no, str(self.password), *kwargs.values())
            )
            self.execute(
                f"INSERT INTO DATA VALUES({', '.join('?' * len(data))})",
                data
            )
            self.commit()

    def change_data(self, no: str, select: str, new: str):
        if encrypt(str(self.password), self.password) == self.real_password:
            no = encrypt(no, self.password)
            new = encrypt(new, self.password)
            self.execute(
                f"UPDATE DATA SET {select} = ? WHERE NO = ?", (new, no)
            )
            self.commit()

    def del_data(self, no: str):
        if encrypt(str(self.password), self.password) == self.real_password:
            no = encrypt(no, self.password)
            self.execute("DELETE FROM DATA WHERE NO = ?", (no,))
            self.commit()
            for i, j in enumerate(self.execute("SELECT * FROM DATA")):
                self.execute(
                    "UPDATE DATA SET NO = ? WHERE NO = ?",
                    (encrypt(str(i), self.password), j[0])
                )
            self.commit()

    def display_database(self):
        for index, row in enumerate(self.execute("SELECT AD, SOYAD FROM DATA")):
            if index != 0:
                print(tuple(decrypt(i, self.password) for i in row))

Veritabanını oluşturmak için bu database.py'yi herhangi bir betik dosyasının içine aktardığımızı varsayalım. Yani test.db isminde bir veritabanını ilk defa oluşturuyoruz.

from database import Database

# Veritabanını 2020 sayısıyla şifreliyoruz.
db = Database(
    database="test.db",
    columns=["AD", "SOYAD"],
    password=2020
)

# Değerler veritabanına 2020 şifresine göre değiştirilerek yazılacak.
db.add_data(AD="Ali", SOYAD="Veli")
# Verileri şimdi görebiliriz.
db.display_database()

Çıktı:

('Ali', 'Veli')

Başka bir oturumda, oluşmuş olan bu test.db veritabanına bu kez şifreyi yanlış girerek bağlanırsak; ne veri ekleyebilir, ne veri silebilir, ne veri değiştirebilir, ne de veriyi düzgün görüntüleyebiliriz.

from database import Database

# Oluşmuş olan test.db veritabanına başka
# bir şifre ile bağlanmaya çalışıyoruz.
db = Database(
    database="test.db",
    columns=["AD", "SOYAD"],
    password=1950
)

db.display_database()

Çıktı:

('\x87²¯', '\x9c«²¯')

Elde ettiğimiz çıktı şifre kısmına yazdığımız 1950 sayısına göre oluştu. Ama şifre parametresine 2020 yazsaydık, doğru çıktıyı alırdık.

1 Beğeni

Peki veritabanını 2020 den başka bir sayı ile şifrelemek isteseydim ?

Veritabanını istediğiniz sayı ile şifreleyebilirsiniz. Vurgulamaya çalıştığım şeyin, şifrenin özellikle 2020 olmasıyla ilgisi yok. Vurgulamaya çalıştığım şey şu; eğer veritabanını oluştururken şifre olarak 2020 sayısını kullanırsanız, başka bir oturumda oluşmuş olan bu veritabanına bağlanmaya çalışırken, şifre parametresine 2020 dışında başka bir sayı yazdığınız taktirde, display_database() fonksiyonunu çağırdığınızda bozuk bir içerikle karşılaşırsınız ve veri ekleme, silme, değiştirme gibi işlemleri yapamazsınız. Özetle veritabanını hangi sayıyla şifrelediyseniz, başka oturumlarda da o şifre kullanılmalı. Örnek yeterince açık aslında. Hangi sayıyı şifre olarak kullanacağınız size kalmış.

1 Beğeni

Çok teşekkür ederim size :smiley:
Gayet iyi anladım mantığını .aslında yukardaki örneğinde katkisi oldu :sweat_smile:

Bu yukarıdaki kodlar sadece size fikir vermesi için paylaşıldı. Uygulamanızda kullanacağınız veritabanı programı biraz farklı olsa iyi olur. Bazı kontroller ekleyebilirsiniz. Mesela kullanıcının şifreyi değiştirme imkanını ortadan kaldırırsınız. Veya değiştirilebilir sütunları siz kendinize göre belirleyebilirsiniz. Ayrıca şifreleme algoritmasında da değişiklikler yapabilirsiniz.

1 Beğeni

İlk bahsettiğim algoritmaya şöyle bir örnek verebilirim:

import hashlib, binascii, os

def hash_password(password):
    """Hash a password for storing."""
    salt = hashlib.sha256(os.urandom(60)).hexdigest().encode('ascii')
    pwdhash = hashlib.pbkdf2_hmac('sha512', password.encode('utf-8'), 
                                salt, 100000)
    pwdhash = binascii.hexlify(pwdhash)
    return (salt + pwdhash).decode('ascii')

def verify_password(stored_password, provided_password):
    """Verify a stored password against one provided by user"""
    salt = stored_password[:64]
    stored_password = stored_password[64:]
    pwdhash = hashlib.pbkdf2_hmac('sha512', 
                                  provided_password.encode('utf-8'), 
                                  salt.encode('ascii'), 
                                  100000)
    pwdhash = binascii.hexlify(pwdhash).decode('ascii')
    return pwdhash == stored_password

def encrypt(data, pw): # sadece örnek bir şifreleme algoritması
    assert len(pw) <= len(data)
    pw = len(data) // len(pw) * pw
    pw += pw[:len(data) % len(pw)]
    return (int.from_bytes(data, "big") ^ int.from_bytes(pw, "big")).to_bytes(max(len(data), len(pw)), "big")
    
def load_database(file, pw):
    with open(file, "rb") as f:
        data = f.read(192) # hash'ın uzunluğu hep 192
        if not verify_password(data.decode(), pw):
            raise ValueError("Password is wrong.")
        return encrypt(f.read(), pw.encode())

def save_database(file, pw, data):
    with open(file, "wb") as f:
        f.write(hash_password(pw).encode() + encrypt(data, pw.encode()))


şifre = input("şifreyi girin")

data = b"rastgelebirveri"

save_database("db.txt", şifre, data)

print(load_database("db.txt", şifre))

Ben hala oyunun haritalarını niçin saklamaya çalıştığınızı anlamadım.

2 Beğeni

aslında örnek verdim kendimi geliştirmek için yazıcam

şimdi @dildeolupbiten in verdiği yöntem basit yer değiştirme algoritması @EkremDincel in verdiği yöntemde keyi dosyanın içine kaydetmek peki sizce hangisi daha güvenli

(buarada bu benim yan hesabım :smile:)

Şifreleme algoritmasının aynı olacağını varsayarsak -benimki sadece bir örnekti- ve hash algoritması da yeterince güvenli ise benim verdiğim örneğin asıl artısı şifrenin yanlış olduğunu veriyi deşifre etmeden anlayabilmek oluyor.

1 Beğeni

@dildeolupbiten şimdi size bir şey danışıcam ben bir server-client gereken bir uygulama yapıyorum (Code duel) ve servere gönderilen veya cliente gönderilen verilerin encrypt edilmesini istiyorum ve sizin örnek verdiğiniz gibi bir yer değiştirme algoritması düşünüyorum, belirli bir zaman aralığında şifre rastgele değişecek ama sorunum hem server hemde client tarafına şifreyi açık vermeden ulaştırmak

Mesela diyelim ben istemciyim, programı çalıştırdım. Sonra istemci olarak ne yapabiliyorum? Programı biraz detaylı ve mümkünse açık bir şekilde anlatabilir misiniz? Hangi veriler hangi aşamada neden şifrelenmeliler?

1 Beğeni

Asimetrik şifrelemelere göz atabilirsiniz.

1 Beğeni

Client klavye inputlarinin bilgilerini gönderecek servere ,veya belirli komutlar -INVITE Gibi -,encrypt yapmak istememin sebebi de sonuçta bu bir server, güvenli olmasını istiyorum kendimce böyle çözümler yapmaya çalışıyorum başka bir önerimiz var mı hocam?

Neye karşı güvenli olmasını istiyorsunuz? Nasıl bir tehdit hayal ediyorsunuz?

Bir de bir sorum daha var. Programın tasarım sürecinde şu anda bu kısımla mı ilgileniyorsunuz? Yani kullanıcının yazdığı komut niteliğindeki yazıları, davet taleplerini sunucuya gönderebiliyorsunuz ama onları şifrelenmiş bir şekilde göndermek istiyorsunuz diyebileceğimiz bir aşamada mısınız?

Hayır aslında daha giriş sayılırız ama fikir edinmeye çalışıyorum yani şu anlık düşünüyorum

Arastiricagim


Şu sorulara cevap alamadım.

Açıkçası encrypt edilmeli diye düşünüyorum nedense : D baska biri aynı ipye bağlanıp verileri çekebilir diye de olabilir. Bilmiyorum. Sizin düşünceniz nedir sizce böyle bir şeye gerek var mı?
@dildeolupbiten

hocam cevap alamadım gerçekten merak ediyorum çoğu incelediğim repolarda şifreliyorlardı


mesela: