🐍Python🐍 zajęcia 7 + zadanie

🐍Python🐍 zajęcia 7 + zadanie
Photo by Matthieu Rochette / Unsplash

pętle * szyfrowanie symetryczne & asymetryczne * funkcje skrótu * szyfr Cezara * książka adresowa

📌 1. Funkcje skrótu (hashujące)

Funkcje skrótu to funkcje jednokierunkowe – nie można z nich odzyskać oryginalnej wiadomości. Używane np. do haszowania haseł.

🔒 2. Szyfrowanie symetryczne – cryptography.fernet

ten sam klucz do szyfrowania i odszyfrowania

Zalety (plusy):

  1. Szybkość
    • Bardzo szybkie szyfrowanie i odszyfrowywanie, nawet dużych ilości danych.
    • Idealne do szyfrowania plików, dysków, transmisji strumieniowej.
  2. Prostota implementacji
    • Łatwiejsze do zaimplementowania niż asymetryczne.
  3. Mniejsze zużycie zasobów
    • Zużywa mniej CPU i pamięci niż szyfrowanie asymetryczne (np. RSA).

Wady (minusy):

  1. Problem z dystrybucją klucza (Key Distribution Problem)
    • Obie strony muszą posiadać ten sam tajny klucz, a jego bezpieczne przekazanie jest trudne (szczególnie przez internet).
  2. Brak weryfikacji tożsamości
    • Samo szyfrowanie symetryczne nie zapewnia, kto wysłał dane. Może być potrzebne dodatkowe uwierzytelnienie.
  3. Brak rozdzielenia ról
    • Każdy, kto ma klucz, może szyfrować i odszyfrowywać – trudniej kontrolować dostępność i uprawnienia.
  4. Nieodporność na podsłuch bez dodatkowych mechanizmów
    • Jeśli klucz zostanie przechwycony, cała komunikacja jest zagrożona.

🔑 3. Szyfrowanie asymetryczne – cryptography.hazmat (RSA)

para kluczy: publiczny i prywatny

Zalety (plusy):

  1. Brak problemu z przesyłaniem klucza
    • Klucz publiczny można bezpiecznie udostępniać każdemu – tylko klucz prywatny musi być chroniony.
    • Rozwiązuje problem dystrybucji klucza znany z szyfrowania symetrycznego.
  1. Możliwość podpisu cyfrowego
    • Umożliwia uwierzytelnianie nadawcy i integralność danych.
    • Klucz prywatny służy do podpisywania, a publiczny do weryfikacji.
  1. Rozdzielenie funkcji szyfrowania i odszyfrowywania
    • Jedna strona szyfruje, druga odszyfrowuje – większa kontrola.
  1. Bezpieczne kanały komunikacji
    • Podstawa działania HTTPS, SSL, VPN, PGP.

❌ Wady (minusy):

  1. Wolniejsze działanie
    • Dużo wolniejsze niż szyfrowanie symetryczne, zwłaszcza przy dużych danych.
    • Często używane tylko do szyfrowania klucza sesyjnego, a reszta danych szyfrowana jest już symetrycznie (np. w HTTPS).
  1. Złożoność algorytmów
    • Trudniejsze do zaimplementowania i zrozumienia.
    • Wymaga dłuższych kluczy (np. 2048 bitów dla RSA), co wpływa na wydajność.
  • Zwiększone zużycie zasobów
    • Większe obciążenie procesora i pamięci, szczególnie na urządzeniach o ograniczonej mocy

Szyfr cezara

  • szyfr przesuwający
  • jest szczególnym przypadkiem szyfru podstawieniowego, w którym każdy znak szyfrowanej wiadomości jest zastępowany innym, oddalonym od niego w alfabecie o określoną odległość

Przykład:

szyfr = 3:

Alfabet: AĄBC ĆDEĘ FGHI JKLŁ MNŃO ÓPRS ŚTUW YZŹŻ
Szyfr: CĆDE ĘFGH IJKL ŁMNŃ OÓPR SŚTU WYZŹ ŻAĄB

Program szyfrujący

ZNAKI = (
    "a",
    "b",
    "c",
    "d",
    "e",
    "f",
    "g",
    "h",
    "i",
    "j",
    "k",
    "l",
    "m",
    "n",
    "o",
    "p",
    "q",
    "r",
    "s",
    "t",
    "u",
    "v",
    "w",
    "x",
    "y",
    "z",
    "A",
    "B",
    "C",
    "D",
    "E",
    "F",
    "G",
    "H",
    "I",
    "J",
    "K",
    "L",
    "M",
    "N",
    "O",
    "P",
    "Q",
    "R",
    "S",
    "T",
    "U",
    "V",
    "W",
    "X",
    "Y",
    "Z",
    "Ą",
    "ą",
    "Ć",
    "ć",
    "Ę",
    "ę",
    "Ł",
    "ł",
    "Ń",
    "ń",
    "Ó",
    "ó",
    "Ś",
    "ś",
    "Ź",
    "ź",
    "Ż",
    "ż",
    " ",
    ".",
    "?",
    "!",
)
# powyższa lista znaków ułatwi stworzenie kodu odpowiedzialnego za szyfrowanie
# żeby przy bardzo dużym kluczu , lub przy zamianie znaku z końca listy nie wyjść za nią
# można skorzystać z operatora modulo (to ten od reszty z dzielenia)
# wg. schematu (indeksznaku + klucz) % len(ZNAKI)

# indeksznaku = ZNAKI.index("!")
# print(f"Indeks znaku ! to: {indeksznaku}")

# klucz = 3
# nowy_indeks = (indeksznaku + klucz) % len(ZNAKI)
# print(f"Po przesunieciu o {klucz} uzyskamy {nowy_indeks}")


# znak= (input('Jaki jest Twoj znak?'))          
# for 
#     zakodowany_znak= int(znak) + (klucz)
#     print(zakodowany_znak)


##### ROZWIĄZANIE 1 dla liter

# znak= (input('Jaki jest Twoj znak?'))
            
# if znak in ZNAKI:
#     liczba_szyfrujaca = ZNAKI.index(znak)
#     print(f'Liczba szyfrująca tego znaku to: {liczba_szyfrujaca}')
# else:
#     print('Ten znak nie znajduje się na liście!')


# klucz = 3
# nowy_indeks = (liczba_szyfrujaca + klucz) % len(ZNAKI)
# print(f"Po przesunieciu o {klucz} uzyskamy {nowy_indeks}")

# nowy_znak = ZNAKI[nowy_indeks]
# print(f"Znak po przesunięciu to: {nowy_znak}")

##### Rozwiązanie 2 dla słów

# do_zaszyfrowania = input("wprowadż tekst do zaszyfrowania: ")
# klucz = int(input("wprowadź liczbę będącą liczbą szyfrującą: "))

# #ADA

# for kazda_litera in do_zaszyfrowania:
#     indeks_znaku = ZNAKI.index(kazda_litera)
#     indeks_zaszyfrowany = (indeks_znaku + klucz) % len(ZNAKI)
#     print("Indeks przed zaszyfrowaniu:", indeks_znaku)
#     print("Indeks po szyfrowaniu:", indeks_zaszyfrowany)
#     znak_zaszyfrowany = ZNAKI[indeks_zaszyfrowany]
#     print(znak_zaszyfrowany)


##### Rozwiązanie 3 do tekstów

do_zaszyfrowania = input("wprowadż tekst do zaszyfrowania: ")
klucz = int(input("wprowadź liczbę będącą liczbą szyfrującą: "))

zaszyfrowany = ""     #Twrorzę zmienną zaszyfrowany, która jest pusta. Do niej potem wrzucany jest tekst zaszyfrowany
for kazda_litera in do_zaszyfrowania:
    indeks_znaku = ZNAKI.index(kazda_litera)
    indeks_zaszyfrowany = (indeks_znaku + klucz) % len(ZNAKI)
    znak_zaszyfrowany = ZNAKI[indeks_zaszyfrowany]
    zaszyfrowany += znak_zaszyfrowany

print("Zaszyfrowany tekst: ", zaszyfrowany)

Zadanie - książka adresowa

struktura danych:

  • słownik

kontakty = {imie_1 : email_1, imie_2 : email_2 ...}

funkcje:

  • usuwanie elementu z listy:

"jeśli imię jest w kontaktach, usuń ("del") kontakty[imie]

  • aktualizacja:

# Książka adresowa
kontakty = {
    "Kasia": "[email protected]",
    "Basia": "[email protected]",
    "Brad" : "[email protected]"   
   
}




while True:
    menu = '''
Menu
    1 - dopisanie pozycji do książki
    2 - aktualizacja pozycji książki
    3 - usunięcie pozycji z książki
    4 - wydruk imion z książki
    5 - wydruk całej książki z kontaktami
    6 - koniec programu
'''
  print(menu)
    
    
    wybor = int(input("Podaj numer operacji, którą chcesz wykonać: "))
    if wybor == 1:
        imie = input("Podaj imię: ")
        if imie not in kontakty:
            email = input(f"Podaj email dla kontaktu {imie}: ")
            kontakty[imie] = email
            print("Dodano kontakt.")
        else:
            print("Ta pozycja już istnieje.")
    elif wybor == 2:
        imie = input("Podaj imię kontaktu do aktualizacji: ")
        if imie in kontakty:
            nowy_email = input("Podaj nowy e-mail: ")
            kontakty[imie] = nowy_email 
            print("Zaktualizowano kontakt.")
        else:
            print("Nie znaleziono takiego kontaktu.")
    elif wybor == 3:
        imie = input("Kogo chcesz usunąć? ")
        if imie in kontakty:
            del kontakty[imie]
            print(f"Usunięto kontakt: {imie}")
        else:
            print("Nie znaleziono takiego kontaktu.")
    elif wybor == 4:
        for imie in kontakty:
            print(imie, end=", ")
    elif wybor == 5:
        print(kontakty)
    else:
        print("Dziękuję za skorzystanie z aplikacji. ")
        break

Do dodania:

  • wersja 3: Mając bazowy produkt warto się zastanowić co może pójść w trakcie korzystania z aplikacji nie tak. Warto obsłużyć takie sytuacje - np. gdy użytkownik spróbuje usunąć kontakt który nie istnieje należy to sprawdzić - i jeśli faktycznie kontaktu nie ma wyświetlić odpowiedni komunikat bez podejmowania próby usunięcia wpisu (co “wywaliłoby” nasz program)
  • kosmetyka: Tu możemy się zająć tym jak wyświetlić poszczególne wybory menu w bardziej przyjazny dla odbiorcy sposób np. wybierając opcję “Wyświetl całą książkę z kontaktami” fajnie jeśli użytkownik otrzyma nie po prostu wydruk słownika, tylko np. nazwę, poniżej danej kontaktowe, poniżej jakieś rozdzielenie (np. serię *), po czym następny kontakt.