Python #7 (szyfrowanie, turtle part 2, pętle)
Szyfrowanie
Funkcja skrótu (hash)
- nie należy jej mylić z szyfrowaniem
- to specjalny algorytm, który zamienia dowolne dane wejściowe w krótki, stałej długości ciąg znaków (tzw. skrót, hash)
- działa jednokierunkowo — nie da się z hasha odzyskać oryginalnych danych
- nawet drobna zmiana danych daje zupełnie inny hash
- zawsze zwraca skrót o tej samej długości, niezależnie od wielkości danych wejściowych
- po co? -> umożliwia przechowywanie w serwisach hashy zamiast haseł; możemy z pomocą hasha zweryfikować czy przesłany plik nie został zmodyfikowany; możemy namierzyć wirusa po jego hashu; słowniki i sety korzystają z funkcji skrótu w celu wskazania miejsca gdzie są nasze dane.
- Szyfrowanie symetryczne - to metoda ochrony danych, w której ten sam tajny klucz służy do szyfrowania (kodowania) wiadomości oraz odszyfrowania (odkodowania) tej samej wiadomości.
- Nadawca i odbiorca muszą wcześniej ustalić wspólny tajny klucz.
- Nadawca: używa klucza i algorytmu szyfrowania, aby przekształcić dane jawne w zaszyfrowane.
- Odbiorca: używa tego samego klucza i algorytmu, by przekształcić dane z powrotem do postaci jawnej.
WADY:
- Problem z przekazaniem klucza — trzeba go dostarczyć odbiorcy w bezpieczny sposób (np. osobiście, przez kanał szyfrowany).
- Słaba skalowalność — w sieci wielu użytkowników każdy musi mieć oddzielne klucze z każdym innym użytkownikiem.
- Brak uwierzytelnienia — nie można udowodnić, kto wysłał wiadomość, bo każdy z kluczem może tworzyć wiadomości.
- Szyfrowanie asymetryczne (zwane też kryptografią klucza publicznego) to metoda, w której używa się dwóch różnych kluczy:
- klucz publiczny – może znać każdy (do szyfrowania),
- klucz prywatny – zna tylko właściciel (do odszyfrowania).
To, co zaszyfrujesz kluczem publicznym, może odszyfrować tylko odpowiadający mu klucz prywatny, i odwrotnie.
Każdy użytkownik generuje parę kluczy (publiczny + prywatny).
- Nadawca:
- pobiera klucz publiczny odbiorcy,
- szyfruje nim wiadomość.
- Odbiorca:
- używa swojego klucza prywatnego do odszyfrowania wiadomości.
Dzięki temu nie trzeba przesyłać żadnych tajnych kluczy — klucz publiczny może być dostępny dla wszystkich.
WADY:
- jest wolniejsze niż symetryczne (więcej obliczeń),
- klucze są dłuższe i bardziej złożone,
- zwykle stosuje się je tylko do przesyłania kluczy symetrycznych, a nie do szyfrowania dużych plików.
W praktyce używamy:
szyfrowanie asymetryczne -> do wymiany kluczy,
szyfrowanie symetryczne -> do szybkiego szyfrowania danych.
Obie metody są często łączone (np. w protokole HTTPS).
- Szyfr Cezara to jeden z najstarszych i najprostszych szyfrów, używany już w starożytnym Rzymie przez Juliusza Cezara do tajnej korespondencji.
To przykład szyfru podstawieniowego, czyli takiego, w którym każda litera tekstu jawnego jest zastępowana inną literą — przesuniętą o stałą liczbę pozycji w alfabecie.
- Wybierasz klucz – liczbę przesunięcia (np. 3).
- Każdą literę przesuwasz w alfabecie o tyle miejsc w prawo. Jeżeli jest to lista - przesuwasz o indeksy. Gdy dojdziemy do końca listy -> zawijamy z powrotem na początek.
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",
"Ą",
"ą",
"Ć",
"ć",
"Ę",
"ę",
"Ł",
"ł",
"Ń",
"ń",
"Ó",
"ó",
"Ś",
"ś",
"Ź",
"ź",
"Ż",
"ż",
" ",
".",
"?",
"!",
]
zdanie = input("Wprowadź zdanie w języku polskim: ")
klucz = int(input("Zaproponuj klucz (cyfra w zakresie 1-9): "))
zaszyfrowany = ""
for znak in zdanie:
index_znaku = ZNAKI.index(znak)
zaszyfrowany += ZNAKI[(index_znaku + klucz) % len(ZNAKI)]
print(f"Po przesunieciu o {klucz} uzyskamy {zaszyfrowany}")
# 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}")
# jeśli nie chcemy skorzystać z naszej własnej tablicy znaków,
# to można to też zrobic korzystajac z tablicy znaków Unicode.
# Przydadzą się wtedy funkcje:
# ord - zwraca nr unicode znaku
# chr - zwraca znak po podaniu nr unicodeTurtle i ciąg Fibonacciego
# Fibonacci graficznie - kwadraty w połowie wypełnione kolorem
import turtle
import random
zolwik = turtle.Turtle() # stworz obiekt rysujacego zolwia pod zmienna zolwik
zolwik.speed(1) # ustaw szybkosc zolwia wbudowana metoda speed
zolwik.shape("turtle") # uzyj metody shape do ustawienia wygladu kursora / zolwia
zolwik.pensize(3)
n = 77
fib = [0, 1]
nast = fib[-2] + fib[-1]
while nast <= n:
fib.append(nast)
nast = fib[-2] + fib[-1]
print(fib)
kolory = [
"CornflowerBlue",
"DarkOrchid",
"IndianRed",
"DeepSkyBlue",
"LightSeaGreen",
"wheat",
"SlateGray",
"SeaGreen",
]
dlugosc_boku = 25
while True:
for mnoznik in fib[1:]:
zolwik.fillcolor(random.choice(kolory))
for _ in range(5):
zolwik.begin_fill()
zolwik.forward(dlugosc_boku*mnoznik)
zolwik.left(90)
zolwik.forward(dlugosc_boku*mnoznik)
zolwik.end_fill()
turtle.exitonclick()
# Fibonacci graficznie - kwadraty całe wypełnione kolorem
import turtle
import random
zolwik = turtle.Turtle() # stworz obiekt rysujacego zolwia pod zmienna zolwik
zolwik.speed(1) # ustaw szybkosc zolwia wbudowana metoda speed
zolwik.shape("turtle") # uzyj metody shape do ustawienia wygladu kursora / zolwia
zolwik.pensize(3)
n = 77
fib = [0, 1]
nast = fib[-2] + fib[-1]
while nast <= n:
fib.append(nast)
nast = fib[-2] + fib[-1]
print(fib)
kolory = [
"CornflowerBlue",
"DarkOrchid",
"IndianRed",
"DeepSkyBlue",
"LightSeaGreen",
"wheat",
"SlateGray",
"SeaGreen",
]
dlugosc_boku = 25
while True:
for mnoznik in fib[1:]:
zolwik.fillcolor(random.choice(kolory))
zolwik.begin_fill()
for _ in range(5):
zolwik.forward(dlugosc_boku*mnoznik)
zolwik.left(90)
zolwik.end_fill()
zolwik.forward(dlugosc_boku*mnoznik)
turtle.exitonclick()Zadanie. Książka kontaktów
# imie / pseudonim
# dane kontaktowe (dowolne - tel, / email)
# dodawanie, aktualizacja, usuwanie
# wybor dziwnego wariantu
kontakty = {"Alice" : "[email protected]",
"Bob" : "[email protected]"
}
def nowy_kontakt():
pseudonim = input("Podaj pseudonim: ").strip()
if pseudonim in kontakty.keys():
print("Taki kontakt już istnieje!")
else:
dane = input("Podaj e-mail): ").strip()
kontakty[pseudonim] = dane
print("Dodano nowy kontakt")
print("***************")
def aktualizacja_kontaktu():
wybrany_kontakt = input("Wybierz imię/pseudonim do modyfikacji: ").strip()
if wybrany_kontakt in kontakty:
kontakty[wybrany_kontakt] = input("Wprowadź nowe dane kontaktowe: ").strip()
else:
print("Taki kontakt już istnieje!")
def usuwanie_kontaktow():
pseudonimdelete = input("Wprowadź imię/pseudonim kontaktu do usunięcia: ").strip()
if pseudonimdelete in kontakty.keys():
kontakty.pop(pseudonimdelete) # lub del kontakty[pseudonimdelete]
print("Kontakt usunięty")
print("***************")
else:
print("Nie ma takiej pozycji w kontaktach")
print("***************")
def wyswietlanie_kontaktow():
for imie, dane in kontakty.items():
print(f"{imie}: {dane}")
print("***************")
def wyswietlenie_wybranego():
wybrany_kontakt = input("Podaj imię/pseudonim kontaktu: ").strip()
if wybrany_kontakt in kontakty:
print(wybrany_kontakt)
print(kontakty[wybrany_kontakt])
print("***************")
while True:
print("Książka kontaktowa:")
print("Wybierz operację:")
print("1 - dodanie wpisu")
print("2 - aktualizacja wpisu")
print("3 - usunięcie wpisu")
print("4 - wydruk wszystkich kontaktów")
print("5 - wydruk konretntego kontaktu")
print("6 - koniec programu")
wybor = input("Podaj kod operacji: ").strip()
if wybor == "1":
print("1")
nowy_kontakt()
elif wybor == "2":
print("2")
aktualizacja_kontaktu()
elif wybor == "3":
print("3")
usuwanie_kontaktow()
elif wybor == "4":
print("4")
wyswietlanie_kontaktow()
elif wybor == "5":
print("5")
wyswietlenie_wybranego()
elif wybor == "6":
print("Koniec programu")
break
else:
print("Nie ma opcji o podanym kodzie.") # # Zadanie - kwestionariusz
# Zbudowaliśmy strukturę danych dla kwestionariusza - wygląda ona tak:
# ```python
# quiz = [
# {
# "pytanie": "tresc pytania",
# "odpowiedzi": [
# ("odp1", 1),
# ("odp2", 0),
# ("odp3", 0),
# ],
# },
# ]
# ```
# ## Baza - użyj pętli do wyświetlenia pytań.
# Użyj pętli `for` żeby wyświetlić użytkownikowi pytania i możliwe warianty odpowiedzi.
# ## Krok 1 - dodaj losową kolejność odpowiedzi
# Skorzystaj z biblioteki `random` i dostępnej w niej funkcji `shuffle` do przemieszania kolejności odpowiedzi. Jeśli masz nr / literkę odpowiedzi dodaną w jej treści - na razie nie przejmuj się tym. Na tym etapie jeszcze nie liczymy też pkt. - zajmujemy się jedynie wyświetlaniem zawartości.
# ## Co dalej?
# Dążymy do tego, żeby w pętli obsłużyć też zliczanie punktów. Jakie kłopoty na tym etapie widzę?
# - jeśli pomieszam kolejność odpowiedzi to jak przypisywać to co wpisał użytkownik z punktacją (czyli np. "a" nie będzie już na pierwszej pozycji tylko np. na trzeciej - co z tym zrobić)?
# - co zrobić żeby "pomieszać" też pytania?
# - dobrze by było na początku poprosić użytkownika o imię etc. Jakiej struktury danych do tego moglibyśmy użyć?
print("*************************")
print("""Witaj w quizie Python""")
print("*************************")
print("Zaczynamy!")
dane_gracza = input("Podaj swoje imię: ")
print("")
punkty = 0
baza_pytan = [
{
"pytanie" : "Gdzie w komórce eukariotycznej znajduje się DNA?",
"odpowiedzi" : [
("w jądrze komórkowym", 1),
("w wakuoli", -1),
("w cytoplazmie", -1)
]
} ,
{
"pytanie" : "Jaką strukturę przestrzenną ma cząsteczka DNA?",
"odpowiedzi" : [
("Podwójna helisa", 1),
("Potrójna spirala", -1),
("Potrójna helisa", -1)
]
} ,
{
"pytanie" : "Która zasada azotowa łączy się zawsze z tyminą?",
"odpowiedzi" : [
("Guanina", -1),
("Adenina", 1),
("Cytozyna", -1)
]
} ,
{
"pytanie" : "Z jakich zasad azotowych zbudowany jest DNA?",
"odpowiedzi" : [
("Adenina, Tymina, Cytozyna, Guanina", 1),
("Adenina, Uracyl, Cytozyna, Guanina", -1),
("Adenina, Tyrozyna, Cysteina, Glutamina", -1)
]
} ,
{
"pytanie" : "Jaką rolę pełni DNA w organizmach żywych?",
"odpowiedzi" : [
("Odpowiada za transport tlenu", -1),
("Dostarcza energii do reakcji komórkowych", -1),
("Jest nośnikiem informacji genetycznej", 1)
]
}
]
import random
pytania_pomieszane = baza_pytan.copy()
random.shuffle(pytania_pomieszane)
for pytanie in pytania_pomieszane:
print("\n" , pytanie["pytanie"])
for i, (odp, punkty_odp) in enumerate(pytanie["odpowiedzi"], start=1):
print(f"{i}. {odp}")
wybor = int(input("Wybierz odpowiedź (numer 1, 2 lub 3): "))
while True:
try:
wybor = int(input("Wybierz odpowiedź (numer 1, 2 lub 3): "))
if 1 <= wybor <= 3:
break
else:
wybor = int(input("Wybierz odpowiedź (numer 1, 2 lub 3): "))
except ValueError:
print("To nie jest liczba! Spróbuj ponownie.")
punkty += pytanie["odpowiedzi"][wybor-1][1]
print("\n***************************************")
print(f"Twoja liczba punktów to {punkty}/5")
if punkty >= 3:
print("Test zaliczony. Gratulacje!")
else:
print("Spróbuj jeszcze raz")
print("\n***************************************")